From hassan.shahbazi at somia.fi Sun Nov 1 00:20:10 2020 From: hassan.shahbazi at somia.fi (Hassan Shahbazi) Date: Sun, 1 Nov 2020 02:20:10 +0200 Subject: [PATCH] staging: fbtft: fb_watterott: fix usleep_range is preferred over udelay Message-ID: <20201101002010.278537-1-hassan@ninchat.com> Fix the checkpath.pl issue on fb_watterott.c. write_vmem and write_vmem_8bit functions are within non-atomic context and can safely use usleep_range. see Documentation/timers/timers-howto.txt Signed-off-by: Hassan Shahbazi --- drivers/staging/fbtft/fb_watterott.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c index 76b25df376b8..afcc86a17995 100644 --- a/drivers/staging/fbtft/fb_watterott.c +++ b/drivers/staging/fbtft/fb_watterott.c @@ -84,7 +84,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) par->txbuf.buf, 10 + par->info->fix.line_length); if (ret < 0) return ret; - udelay(300); + usleep_range(300, 310); } return 0; @@ -124,7 +124,7 @@ static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) par->txbuf.buf, 10 + par->info->var.xres); if (ret < 0) return ret; - udelay(700); + usleep_range(700, 710); } return 0; -- 2.25.1 From info1 at foescoformacion.es Sun Nov 1 03:14:18 2020 From: info1 at foescoformacion.es (FOESCO) Date: Sun, 1 Nov 2020 04:14:18 +0100 Subject: =?Windows-1252?Q?Formaci=F3n_Bonificable_(=DAltimo_plazo_de_inscr?= =?Windows-1252?Q?ipci=F3n_2020)?= Message-ID: <59364081696402863615681@DESKTOP-MFVDD89> Buenos d?as Os informamos que se encuentra abierto el plazo de inscripci?n para la "?LTIMA CONVOCATORIA 2020" de Cursos Bonificables para empleados en activo y en ERTE. Los cursos son 100% Bonificables con cargo al Cr?dito de Formaci?n 2020, si vuestra empresa todav?a dispone de Cr?dito de Formaci?n 2020 esta es la ?ltima oportunidad para poder consumirlo. Dese?is que os mandemos la informaci?n? Quedamos a la espera de vuestra respuesta. Saludos cordiales. Alex Pons Director FOESCO. FOESCO Formaci?n Estatal Continua. Entidad Organizadora: B200592AA www.foesco.com e-mail: cursos at foesco.net Tel: 910 323 794 (Horario de 9h a 15h y de 17h a 20h de Lunes a Viernes) FOESCO ofrece formaci?n a empresas y trabajadores en activo a trav?s de cursos bonificados por la Fundaci?n Estatal para la Formaci?n en el Empleo (antiguo FORCEM) que gestiona las acciones formativas de FORMACI?N CONTINUA para trabajadores y se rige por la ley 30/2015 de 9 de Septiembre. Antes de imprimir este e-mail piense bien si es necesario hacerlo. Before printing this e-mail please think twice if you really need it. FOESCO Tfno: 910 382 880 Email: cursos at foesco.com. La informaci?n transmitida en este mensaje est? dirigida solamente a las personas o entidades que figuran en el encabezamiento y contiene informaci?n confidencial, por lo que, si usted lo recibiera por error, por favor destr?yalo sin copiarlo, usarlo ni distribuirlo, comunic?ndolo inmediatamente al emisor del mensaje. De conformidad con lo dispuesto en el Reglamento Europeo del 2016/679, del 27 de Abril de 2016, FOESCO le informa que los datos por usted suministrados ser?n tratados con las medidas de seguridad conformes a la normativa vigente que se requiere. Dichos datos ser?n empleados con fines de gesti?n. Para el ejercicio de sus derechos de transparencia, informaci?n, acceso, rectificaci?n, supresi?n o derecho al olvido, limitaci?n del tratamiento , portabilidad de datos y oposici?n de sus datos de car?cter personal deber? dirigirse a la direcci?n del Responsable del tratamiento a C/ LAGUNA DEL MARQUESADO N?10, 28021, MADRID, "PULSANDO AQUI" y "ENVIAR" o a traves de la direcci?n de correo electr?nico: bajas at foesco.com From greg at kroah.com Sun Nov 1 06:39:48 2020 From: greg at kroah.com (Greg KH) Date: Sun, 1 Nov 2020 07:39:48 +0100 Subject: [PATCH] staging: fbtft: fb_watterott: fix usleep_range is preferred over udelay In-Reply-To: <20201101002010.278537-1-hassan@ninchat.com> References: <20201101002010.278537-1-hassan@ninchat.com> Message-ID: <20201101063948.GB432418@kroah.com> On Sun, Nov 01, 2020 at 02:20:10AM +0200, Hassan Shahbazi wrote: > Fix the checkpath.pl issue on fb_watterott.c. write_vmem and > write_vmem_8bit functions are within non-atomic context and can > safely use usleep_range. > see Documentation/timers/timers-howto.txt > > Signed-off-by: Hassan Shahbazi > --- > drivers/staging/fbtft/fb_watterott.c | 4 ++-- > 1 file changed, 2 insertions(+), 2 deletions(-) > > diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c > index 76b25df376b8..afcc86a17995 100644 > --- a/drivers/staging/fbtft/fb_watterott.c > +++ b/drivers/staging/fbtft/fb_watterott.c > @@ -84,7 +84,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) > par->txbuf.buf, 10 + par->info->fix.line_length); > if (ret < 0) > return ret; > - udelay(300); > + usleep_range(300, 310); > } > > return 0; > @@ -124,7 +124,7 @@ static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) > par->txbuf.buf, 10 + par->info->var.xres); > if (ret < 0) > return ret; > - udelay(700); > + usleep_range(700, 710); How do you know that these ranges are ok? Are you able to test these changes with real hardware? thanks, greg k-h From hassan.shahbazi at somia.fi Sun Nov 1 10:32:44 2020 From: hassan.shahbazi at somia.fi (Hassan Shahbazi) Date: Sun, 1 Nov 2020 12:32:44 +0200 Subject: [PATCH] staging: fbtft: fb_watterott: fix usleep_range is preferred over udelay In-Reply-To: <20201101063948.GB432418@kroah.com> References: <20201101002010.278537-1-hassan@ninchat.com> <20201101063948.GB432418@kroah.com> Message-ID: <20201101103244.GA284952@ubuntu> On Sun, Nov 01, 2020 at 07:39:48AM +0100, Greg KH wrote: > On Sun, Nov 01, 2020 at 02:20:10AM +0200, Hassan Shahbazi wrote: > > Fix the checkpath.pl issue on fb_watterott.c. write_vmem and > > write_vmem_8bit functions are within non-atomic context and can > > safely use usleep_range. > > see Documentation/timers/timers-howto.txt > > > > Signed-off-by: Hassan Shahbazi > > --- > > drivers/staging/fbtft/fb_watterott.c | 4 ++-- > > 1 file changed, 2 insertions(+), 2 deletions(-) > > > > diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c > > index 76b25df376b8..afcc86a17995 100644 > > --- a/drivers/staging/fbtft/fb_watterott.c > > +++ b/drivers/staging/fbtft/fb_watterott.c > > @@ -84,7 +84,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) > > par->txbuf.buf, 10 + par->info->fix.line_length); > > if (ret < 0) > > return ret; > > - udelay(300); > > + usleep_range(300, 310); > > } > > > > return 0; > > @@ -124,7 +124,7 @@ static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) > > par->txbuf.buf, 10 + par->info->var.xres); > > if (ret < 0) > > return ret; > > - udelay(700); > > + usleep_range(700, 710); > > How do you know that these ranges are ok? Are you able to test these > changes with real hardware? > > thanks, > > greg k-h No, I don't have the hardware to test with. I just used the current value as the minimum and added an epsilon to it for the maximum param. best, hassan shahbazi From heiko at sntech.de Sun Nov 1 10:54:36 2020 From: heiko at sntech.de (Heiko Stuebner) Date: Sun, 01 Nov 2020 11:54:36 +0100 Subject: [PATCH v6 8/9] arm64: dts: rockchip: add isp0 node for rk3399 In-Reply-To: <20201020193850.1460644-9-helen.koike@collabora.com> References: <20201020193850.1460644-1-helen.koike@collabora.com> <20201020193850.1460644-9-helen.koike@collabora.com> Message-ID: <25468331.GQUMHoxoIT@phil> Am Dienstag, 20. Oktober 2020, 21:38:49 CET schrieb Helen Koike: > From: Shunqian Zheng > > RK3399 has two ISPs, but only isp0 was tested. > Add isp0 node in rk3399 dtsi > > Verified with: > make ARCH=arm64 dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/media/rockchip-isp1.yaml > > Signed-off-by: Shunqian Zheng > Signed-off-by: Jacob Chen > Signed-off-by: Helen Koike looks good, and I'd like to apply this one after the drivers/media-patches of this series got applied. Thanks Heiko > > --- > > Changes in v6: > - Add status = "disabled" in the isp0 node > --- > arch/arm64/boot/dts/rockchip/rk3399.dtsi | 26 ++++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > > diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi > index ada724b12f014..af5f8e2c5e64d 100644 > --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi > +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi > @@ -1723,6 +1723,32 @@ vopb_mmu: iommu at ff903f00 { > status = "disabled"; > }; > > + isp0: isp0 at ff910000 { > + compatible = "rockchip,rk3399-cif-isp"; > + reg = <0x0 0xff910000 0x0 0x4000>; > + interrupts = ; > + clocks = <&cru SCLK_ISP0>, > + <&cru ACLK_ISP0_WRAPPER>, > + <&cru HCLK_ISP0_WRAPPER>; > + clock-names = "isp", "aclk", "hclk"; > + iommus = <&isp0_mmu>; > + phys = <&mipi_dphy_rx0>; > + phy-names = "dphy"; > + power-domains = <&power RK3399_PD_ISP0>; > + status = "disabled"; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + port at 0 { > + reg = <0>; > + #address-cells = <1>; > + #size-cells = <0>; > + }; > + }; > + }; > + > isp0_mmu: iommu at ff914000 { > compatible = "rockchip,iommu"; > reg = <0x0 0xff914000 0x0 0x100>, <0x0 0xff915000 0x0 0x100>; > From heiko at sntech.de Sun Nov 1 10:55:16 2020 From: heiko at sntech.de (Heiko Stuebner) Date: Sun, 01 Nov 2020 11:55:16 +0100 Subject: [PATCH v6 9/9] arm64: dts: rockchip: add isp and sensors for Scarlet In-Reply-To: <20201020193850.1460644-10-helen.koike@collabora.com> References: <20201020193850.1460644-1-helen.koike@collabora.com> <20201020193850.1460644-10-helen.koike@collabora.com> Message-ID: <14722083.QWuEjnDerj@phil> Am Dienstag, 20. Oktober 2020, 21:38:50 CET schrieb Helen Koike: > From: Eddie Cai > > Enable ISP and camera sensor ov2685 and ov5695 for Scarlet Chromebook > > Verified with: > make ARCH=arm64 dtbs_check > > Signed-off-by: Shunqian Zheng > Signed-off-by: Eddie Cai > Signed-off-by: Tomasz Figa > Signed-off-by: Helen Koike > Reviewed-by: Tomasz Figa looks good, and I'd like to apply this one after the drivers/media-patches of this series got applied. Thanks Heiko > --- > .../boot/dts/rockchip/rk3399-gru-scarlet.dtsi | 74 +++++++++++++++++++ > 1 file changed, 74 insertions(+) > > diff --git a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi > index 60cd1c18cd4e0..beee5fbb34437 100644 > --- a/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi > +++ b/arch/arm64/boot/dts/rockchip/rk3399-gru-scarlet.dtsi > @@ -296,6 +296,52 @@ camera: &i2c7 { > > /* 24M mclk is shared between world and user cameras */ > pinctrl-0 = <&i2c7_xfer &test_clkout1>; > + > + /* Rear-facing camera */ > + wcam: camera at 36 { > + compatible = "ovti,ov5695"; > + reg = <0x36>; > + pinctrl-names = "default"; > + pinctrl-0 = <&wcam_rst>; > + > + clocks = <&cru SCLK_TESTCLKOUT1>; > + clock-names = "xvclk"; > + > + avdd-supply = <&pp2800_cam>; > + dvdd-supply = <&pp1250_cam>; > + dovdd-supply = <&pp1800_s0>; > + reset-gpios = <&gpio2 5 GPIO_ACTIVE_LOW>; > + > + port { > + wcam_out: endpoint { > + remote-endpoint = <&mipi_in_wcam>; > + data-lanes = <1 2>; > + }; > + }; > + }; > + > + /* Front-facing camera */ > + ucam: camera at 3c { > + compatible = "ovti,ov2685"; > + reg = <0x3c>; > + pinctrl-names = "default"; > + pinctrl-0 = <&ucam_rst>; > + > + clocks = <&cru SCLK_TESTCLKOUT1>; > + clock-names = "xvclk"; > + > + avdd-supply = <&pp2800_cam>; > + dovdd-supply = <&pp1800_s0>; > + dvdd-supply = <&pp1800_s0>; > + reset-gpios = <&gpio2 3 GPIO_ACTIVE_LOW>; > + > + port { > + ucam_out: endpoint { > + remote-endpoint = <&mipi_in_ucam>; > + data-lanes = <1>; > + }; > + }; > + }; > }; > > &cdn_dp { > @@ -353,10 +399,38 @@ &io_domains { > gpio1830-supply = <&pp1800_s0>; /* APIO4_VDD; 4c 4d */ > }; > > +&isp0 { > + status = "okay"; > + > + ports { > + port at 0 { > + mipi_in_wcam: endpoint at 0 { > + reg = <0>; > + remote-endpoint = <&wcam_out>; > + data-lanes = <1 2>; > + }; > + > + mipi_in_ucam: endpoint at 1 { > + reg = <1>; > + remote-endpoint = <&ucam_out>; > + data-lanes = <1>; > + }; > + }; > + }; > +}; > + > +&isp0_mmu { > + status = "okay"; > +}; > + > &max98357a { > sdmode-gpios = <&gpio0 2 GPIO_ACTIVE_HIGH>; > }; > > +&mipi_dphy_rx0 { > + status = "okay"; > +}; > + > &mipi_dsi { > status = "okay"; > clock-master; > From gregkh at linuxfoundation.org Sun Nov 1 13:09:21 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Sun, 1 Nov 2020 14:09:21 +0100 Subject: [GIT PULL] Staging driver fixes for 5.10-rc2 Message-ID: <20201101130921.GA4115310@kroah.com> The following changes since commit 3650b228f83adda7e5ee532e2b90429c03f7b9ec: Linux 5.10-rc1 (2020-10-25 15:14:11 -0700) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git tags/staging-5.10-rc2 for you to fetch changes up to 7e97e4cbf30026b49b0145c3bfe06087958382c5: staging: fieldbus: anybuss: jump to correct label in an error path (2020-10-27 13:24:51 +0100) ---------------------------------------------------------------- Staging driver fixes for 5.10-rc2 Here are some small staging driver fixes for issues that have been reported in 5.10-rc1: - octeon driver fixes - wfx driver fixes - memory leak fix in vchiq driver - fieldbus driver bugfix - comedi driver bugfix All of these have been in linux-next with no reported issues Signed-off-by: Greg Kroah-Hartman ---------------------------------------------------------------- Alexander Sverdlin (2): staging: octeon: repair "fixed-link" support staging: octeon: Drop on uncorrectable alignment or FCS error Ian Abbott (1): staging: comedi: cb_pcidas: Allow 2-channel commands for AO subdevice Jing Xiangfeng (1): staging: fieldbus: anybuss: jump to correct label in an error path J?r?me Pouiller (2): staging: wfx: fix use of uninitialized pointer staging: wfx: fix test on return value of gpiod_get_value() Seung-Woo Kim (1): staging: mmal-vchiq: Fix memory leak for vchiq_instance drivers/staging/comedi/drivers/cb_pcidas.c | 1 + drivers/staging/fieldbus/anybuss/arcx-anybus.c | 2 +- drivers/staging/octeon/ethernet-mdio.c | 6 ---- drivers/staging/octeon/ethernet-rx.c | 34 ++++++++++++---------- drivers/staging/octeon/ethernet.c | 9 ++++++ .../staging/vc04_services/vchiq-mmal/mmal-vchiq.c | 19 +++++++++--- drivers/staging/wfx/bh.c | 2 +- drivers/staging/wfx/data_tx.c | 6 ++-- 8 files changed, 49 insertions(+), 30 deletions(-) From 04098700 at agranidoer.com Sun Nov 1 15:33:53 2020 From: 04098700 at agranidoer.com (Hello) Date: Sun, 1 Nov 2020 15:33:53 -0000 Subject: Hello friend 01/11/2020 Message-ID: <20201101153422.B7F5786FA3@fraxinus.osuosl.org> My name is Reem Hashimy, the Emirates Minister of State and Managing Director of the United Arab Emirates (Dubai) World Expo 2020 Committee which has been postponed to October 2021 to March 2022 because of the Covid-19 pandemic. I am writing to you to manage the funds I received as financial gratification from various foreign companies I assisted to receive a participation approval to the coming event. The amount is $44,762,906.00 United States dollars. But I can not personally manage the fund in my country because of the sensitive nature of my office and the certain restriction on married Muslim women. For this reason, an agreement was reached with a consulting firm to direct the various financial gifts into an open beneficiary account in my name with a bank where it will be possible for me to instruct the transfer of ownership right to a third party for investment purpose; which is the reason I am contacting you to receive the fund and manage it as my investment partner. Note that the fund is NOT connected to any criminal or terrorist activity. On your indication of interest with your information to include your name, your phone number and contact mailing address; I will instruct the consulting firm to process the fund from the bank to your country for investment purposes. Regards. Reem Hashimy. From wraylemke at compuserve.com Sun Nov 1 14:33:32 2020 From: wraylemke at compuserve.com (Did You Received My Previous Email?) Date: Sun, 1 Nov 2020 06:33:32 -0800 Subject: Pls Reply To My Previous Email. Message-ID: <20201101171358.452D4878C1@fraxinus.osuosl.org> Good morning, I am Ms Birgul Kurnaz from Turkey, I am the head of operations in Charge of Foreign Contact Portfolio matters with Exxon Mobil Corporation Turkey. Did you received the email I sent you before? Please reply is urgent for business. If you did not received it let me know so that I can resendit to you again. Thank you very much. Ms Birgul Kurnaz. DWLFRKDFYEVILBUYEYQEFBTLMKZMNFJWEKYFNW From wraylemke at compuserve.com Sun Nov 1 14:33:32 2020 From: wraylemke at compuserve.com (Did You Received My Previous Email?) Date: Sun, 1 Nov 2020 06:33:32 -0800 Subject: Pls Reply To My Previous Email. Message-ID: <20201101171358.D385E2012F@silver.osuosl.org> Good morning, I am Ms Birgul Kurnaz from Turkey, I am the head of operations in Charge of Foreign Contact Portfolio matters with Exxon Mobil Corporation Turkey. Did you received the email I sent you before? Please reply is urgent for business. If you did not received it let me know so that I can resendit to you again. Thank you very much. Ms Birgul Kurnaz. DWLFRKDFYEVILBUYEYQEFBTLMKZMNFJWEKYFNW From pr-tracker-bot at kernel.org Sun Nov 1 18:09:00 2020 From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org) Date: Sun, 01 Nov 2020 18:09:00 +0000 Subject: [GIT PULL] Staging driver fixes for 5.10-rc2 In-Reply-To: <20201101130921.GA4115310@kroah.com> References: <20201101130921.GA4115310@kroah.com> Message-ID: <160425414064.10555.3823876563045716017.pr-tracker-bot@kernel.org> The pull request you sent on Sun, 1 Nov 2020 14:09:21 +0100: > git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git tags/staging-5.10-rc2 has been merged into torvalds/linux.git: https://git.kernel.org/torvalds/c/2376cca02d73a67ab28f03aa787777b74c3b0230 Thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/prtracker.html From maxime at cerno.tech Mon Nov 2 09:17:37 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Mon, 2 Nov 2020 10:17:37 +0100 Subject: [PATCH 00/14] Allwinner MIPI CSI-2 support for A31/V3s/A83T In-Reply-To: References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> Message-ID: <20201102091737.pszii6znryssyh2e@gilmour.lan> Hi On Fri, Oct 30, 2020 at 07:44:28PM -0300, Helen Koike wrote: > On thing that is confusing me is the name csi2 with csi (that makes me > think of csi vesun6i-csirsion one, which is not the case), I would > rename it to sun6i-video (or maybe it is just me who gets confused). > > I know this driver is already upstream and not part of this series, > but on the other hand it doesn't seem to be used. It's definitely confusing but CSI is the name of the IP, but it supports more than just MIPI-CSI :) Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From maxime at cerno.tech Mon Nov 2 09:21:10 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Mon, 2 Nov 2020 10:21:10 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> Message-ID: <20201102092110.ro6a456lvbrktwoz@gilmour.lan> On Fri, Oct 30, 2020 at 07:45:18PM -0300, Helen Koike wrote: > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > > found on Allwinner SoCs such as the A31 and V3/V3s. > > > > It is a standalone block, connected to the CSI controller on one side > > and to the MIPI D-PHY block on the other. It has a dedicated address > > space, interrupt line and clock. > > > > Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > > controller (CSI0) but newer SoCs (such as the V5) may allow switching > > MIPI CSI-2 controllers between CSI controllers. > > > > It is represented as a V4L2 subdev to the CSI controller and takes a > > MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > > media controller API. > > Maybe this is a bad idea, but I was thinking: > This driver basically just turn on/off and catch some interrupts for errors, > and all the rest of v4l2 config you just forward to the next subdevice > on the pipeline. > > So instead of exposing it as a subdevice, I was wondering if modeling > this driver also through the phy subsystem wouldn't be cleaner, so > you won't need all the v4l2 subdevice/topology boilerplate code that > it seems you are not using (unless you have plans to add controls or > some specific configuration on this node later). > > But this would require changes on the sun6i-csi driver. > > What do you think? Eventually we'll need to filter the virtual channels / datatypes I guess, so it's definitely valuable to have it in v4l2 Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From abbotti at mev.co.uk Mon Nov 2 10:25:25 2020 From: abbotti at mev.co.uk (Ian Abbott) Date: Mon, 2 Nov 2020 10:25:25 +0000 Subject: [PATCH] staging: comedi: cb_pcidas: reinstate delay removed from trimpot setting In-Reply-To: <20201029141833.126856-1-abbotti@mev.co.uk> References: <20201029141833.126856-1-abbotti@mev.co.uk> Message-ID: <3d7cf15a-c389-ec2c-5e29-8838e8466790@mev.co.uk> On 29/10/2020 14:18, Ian Abbott wrote: > Commit eddd2a4c675c ("staging: comedi: cb_pcidas: refactor > write_calibration_bitstream()") inadvertently removed one of the > `udelay(1)` calls when writing to the calibration register in > `cb_pcidas_calib_write()`. Reinstate the delay. It may seem strange > that the delay is placed before the register write, but this function is > called in a loop so the extra delay can make a difference. > > This _might_ solve reported issues reading analog inputs on a > PCIe-DAS1602/16 card where the analog input values "were scaled in a > strange way that didn't make sense". On the same hardware running a > system with a 3.13 kernel, and then a system with a 4.4 kernel, but with > the same application software, the system with the 3.13 kernel was fine, > but the one with the 4.4 kernel exhibited the problem. Of the 90 > changes to the driver between those kernel versions, this change looked > like the most likely culprit. Actually, I've realized that this patch will have no effect on the PCIe-DAS1602/16 card because it uses a different driver - cb_pcimdas, not cb_pcidas. Greg, you might as well drop this patch if you haven't already applied it, since it was only a hunch that it fixed a problem. -- -=( Ian Abbott || MEV Ltd. is a company )=- -=( registered in England & Wales. Regd. number: 02862268. )=- -=( Regd. addr.: S11 & 12 Building 67, Europa Business Park, )=- -=( Bird Hall Lane, STOCKPORT, SK3 0XA, UK. || www.mev.co.uk )=- From abbotti at mev.co.uk Mon Nov 2 11:16:05 2020 From: abbotti at mev.co.uk (Ian Abbott) Date: Mon, 2 Nov 2020 11:16:05 +0000 Subject: [PATCH] staging: comedi: cb_pcidas: reinstate delay removed from trimpot setting In-Reply-To: <3d7cf15a-c389-ec2c-5e29-8838e8466790@mev.co.uk> References: <20201029141833.126856-1-abbotti@mev.co.uk> <3d7cf15a-c389-ec2c-5e29-8838e8466790@mev.co.uk> Message-ID: On 02/11/2020 10:25, Ian Abbott wrote: > On 29/10/2020 14:18, Ian Abbott wrote: >> Commit eddd2a4c675c ("staging: comedi: cb_pcidas: refactor >> write_calibration_bitstream()") inadvertently removed one of the >> `udelay(1)` calls when writing to the calibration register in >> `cb_pcidas_calib_write()`.? Reinstate the delay.? It may seem strange >> that the delay is placed before the register write, but this function is >> called in a loop so the extra delay can make a difference. >> >> This _might_ solve reported issues reading analog inputs on a >> PCIe-DAS1602/16 card where the analog input values "were scaled in a >> strange way that didn't make sense".? On the same hardware running a >> system with a 3.13 kernel, and then a system with a 4.4 kernel, but with >> the same application software, the system with the 3.13 kernel was fine, >> but the one with the 4.4 kernel exhibited the problem.? Of the 90 >> changes to the driver between those kernel versions, this change looked >> like the most likely culprit. > > Actually, I've realized that this patch will have no effect on the > PCIe-DAS1602/16 card because it uses a different driver - cb_pcimdas, > not cb_pcidas. But that's also confusing because PCIe-DAS1602/16 was not supported until the 3.19 kernel! I know the reported has both PCI-DAS1602/16 and PCIe-DAS1602/16 cards (supported by cb_pcidas and cb_pcimdas respectively), so there could have been some mix-up in the reporting. > > Greg, you might as well drop this patch if you haven't already applied > it, since it was only a hunch that it fixed a problem. > -- -=( Ian Abbott || MEV Ltd. is a company )=- -=( registered in England & Wales. Regd. number: 02862268. )=- -=( Regd. addr.: S11 & 12 Building 67, Europa Business Park, )=- -=( Bird Hall Lane, STOCKPORT, SK3 0XA, UK. || www.mev.co.uk )=- From support at clickirr.com Sun Nov 1 09:15:27 2020 From: support at clickirr.com (Julianna Ndoi) Date: Sun, 1 Nov 2020 09:15:27 -0000 Subject: Greetings Message-ID: <5D1F3EC71CB94516A2BE1CEA3A541251.MAI@clickirr.com> Greetings my beloved, My name is Mrs.Julianna Stefan Ndoi,I am a deaf woman and also a cancer patient who had decided to donate what I have to you for God's works. I want to donate $8.5 million to you so that you will use part of the this fund to help the poor ones,while you use the rest for your family.If you are interested,Respond now for more details on how to receive this fund. Regards, Mrs.Julianna,greeting from the sick bed ************************************** Saludos mi amado, Mi nombre es Sra. Julianna Stefan Ndoi, soy una hermana sorda ... Soy una paciente de c?ncer que ten?a Decid? donarles lo que tengo para las obras de Dios. Quiero donar $ 8.5 millones para usted para que use parte de este fondo para ayudar los pobres, mientras que el resto lo usas para tu familia. interesado, responda ahora para obtener m?s detalles sobre c?mo recibir este fondo. Saludos, Se?ora Julianna, saludando desde la cama de enferma From zhangqilong3 at huawei.com Mon Nov 2 14:26:22 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Mon, 2 Nov 2020 22:26:22 +0800 Subject: [PATCH -next] media: cedrus: fix reference leak in cedrus_start_streaming Message-ID: <20201102142622.140001-1-zhangqilong3@huawei.com> pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference leak in cedrus_start_streaming. We should fix it. Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") Signed-off-by: Zhang Qilong --- drivers/staging/media/sunxi/cedrus/cedrus_video.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 667b86dde1ee..911f607d9b09 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -479,8 +479,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) if (V4L2_TYPE_IS_OUTPUT(vq->type)) { ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0) { + pm_runtime_put_noidle(dev->dev); goto err_cleanup; + } if (dev->dec_ops[ctx->current_codec]->start) { ret = dev->dec_ops[ctx->current_codec]->start(ctx); -- 2.17.1 From zhangqilong3 at huawei.com Mon Nov 2 14:28:52 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Mon, 2 Nov 2020 22:28:52 +0800 Subject: [PATCH -next] media: staging: rkisp1: cap: fix runtime PM imbalance on error Message-ID: <20201102142852.141189-1-zhangqilong3@huawei.com> pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference imbalance in rkisp1_vb2_start_streaming, so we should fix it. Fixes: 56e3b29f9f6b2 ("media: staging: rkisp1: add streaming paths") Signed-off-by: Zhang Qilong --- drivers/staging/media/rkisp1/rkisp1-capture.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/rkisp1/rkisp1-capture.c b/drivers/staging/media/rkisp1/rkisp1-capture.c index b6f497ce3e95..0c934ca5adaa 100644 --- a/drivers/staging/media/rkisp1/rkisp1-capture.c +++ b/drivers/staging/media/rkisp1/rkisp1-capture.c @@ -992,6 +992,7 @@ rkisp1_vb2_start_streaming(struct vb2_queue *queue, unsigned int count) ret = pm_runtime_get_sync(cap->rkisp1->dev); if (ret < 0) { + pm_runtime_put_noidle(cap->rkisp1->dev); dev_err(cap->rkisp1->dev, "power up failed %d\n", ret); goto err_destroy_dummy; } -- 2.17.1 From maxime at cerno.tech Mon Nov 2 14:18:38 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Mon, 2 Nov 2020 15:18:38 +0100 Subject: [PATCH -next] media: cedrus: fix reference leak in cedrus_start_streaming In-Reply-To: <20201102142622.140001-1-zhangqilong3@huawei.com> References: <20201102142622.140001-1-zhangqilong3@huawei.com> Message-ID: <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: > pm_runtime_get_sync will increment pm usage counter even it > failed. Forgetting to pm_runtime_put_noidle will result in > reference leak in cedrus_start_streaming. We should fix it. > > Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") > Signed-off-by: Zhang Qilong Shouldn't we fix pm_runtime_get_sync instead then? It seems that most of the callers get this wrong, and that's definitely non-obvious. Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From zhangqilong3 at huawei.com Mon Nov 2 14:39:04 2020 From: zhangqilong3 at huawei.com (zhangqilong) Date: Mon, 2 Nov 2020 14:39:04 +0000 Subject: =?gb2312?B?tPC4tDogW1BBVENIIC1uZXh0XSBtZWRpYTogY2VkcnVzOiBmaXggcmVmZXJl?= =?gb2312?B?bmNlIGxlYWsgaW4gY2VkcnVzX3N0YXJ0X3N0cmVhbWluZw==?= In-Reply-To: <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> References: <20201102142622.140001-1-zhangqilong3@huawei.com> <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> Message-ID: Hi > > On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: > > pm_runtime_get_sync will increment pm usage counter even it failed. > > Forgetting to pm_runtime_put_noidle will result in reference leak in > > cedrus_start_streaming. We should fix it. > > > > Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") > > Signed-off-by: Zhang Qilong > > Shouldn't we fix pm_runtime_get_sync instead then? It seems that most of the > callers get this wrong, and that's definitely non-obvious. > I have ever thought to fix fix pm_runtime_get_sync, then I went to read the comment on this function, and found that this is what the author intended to do(comment: The possible return values of this function are the same as for pm_runtime_resume() and the runtime PM usage counter of @dev remains incremented in all cases, even if it returns an error code). On the other hand, I found that the number of callers that getting this right is much bigger than getting this wrong even many callers get wrong. So I submit server patches to fix them as I could. Thanks, best wish! Zhang Qilong > Maxime From christian.gromm at microchip.com Mon Nov 2 15:14:03 2020 From: christian.gromm at microchip.com (Christian Gromm) Date: Mon, 2 Nov 2020 16:14:03 +0100 Subject: [PATCH] drivers: most: add ALSA sound driver Message-ID: <1604330043-5517-1-git-send-email-christian.gromm@microchip.com> This patch moves the ALSA sound driver out of the staging area and adds it to the stable part of the MOST driver. Modifications to the Makefiles and Kconfigs are done accordingly to not break the build. Signed-off-by: Christian Gromm --- drivers/most/Kconfig | 10 + drivers/most/Makefile | 1 + drivers/most/most_snd.c | 753 ++++++++++++++++++++++++++++++++++++ drivers/staging/most/Kconfig | 2 - drivers/staging/most/Makefile | 1 - drivers/staging/most/sound/Kconfig | 14 - drivers/staging/most/sound/Makefile | 4 - drivers/staging/most/sound/sound.c | 753 ------------------------------------ 8 files changed, 764 insertions(+), 774 deletions(-) create mode 100644 drivers/most/most_snd.c delete mode 100644 drivers/staging/most/sound/Kconfig delete mode 100644 drivers/staging/most/sound/Makefile delete mode 100644 drivers/staging/most/sound/sound.c diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig index ebfe84e..4b8145b 100644 --- a/drivers/most/Kconfig +++ b/drivers/most/Kconfig @@ -32,4 +32,14 @@ config MOST_CDEV To compile this driver as a module, choose M here: the module will be called most_cdev. + +config MOST_SND + tristate "Sound" + depends on SND + select SND_PCM + help + Say Y here if you want to commumicate via ALSA/sound devices. + + To compile this driver as a module, choose M here: the + module will be called most_sound. endif diff --git a/drivers/most/Makefile b/drivers/most/Makefile index 8b53ca4..60db6cd 100644 --- a/drivers/most/Makefile +++ b/drivers/most/Makefile @@ -5,3 +5,4 @@ most_core-y := core.o \ obj-$(CONFIG_MOST_USB_HDM) += most_usb.o obj-$(CONFIG_MOST_CDEV) += most_cdev.o +obj-$(CONFIG_MOST_SND) += most_snd.o diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c new file mode 100644 index 0000000..8a449ab --- /dev/null +++ b/drivers/most/most_snd.c @@ -0,0 +1,753 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sound.c - Sound component for Mostcore + * + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sound" +#define STRING_SIZE 80 + +static struct most_component comp; + +/** + * struct channel - private structure to keep channel specific data + * @substream: stores the substream structure + * @iface: interface for which the channel belongs to + * @cfg: channel configuration + * @card: registered sound card + * @list: list for private use + * @id: channel index + * @period_pos: current period position (ring buffer) + * @buffer_pos: current buffer position (ring buffer) + * @is_stream_running: identifies whether a stream is running or not + * @opened: set when the stream is opened + * @playback_task: playback thread + * @playback_waitq: waitq used by playback thread + */ +struct channel { + struct snd_pcm_substream *substream; + struct snd_pcm_hardware pcm_hardware; + struct most_interface *iface; + struct most_channel_config *cfg; + struct snd_card *card; + struct list_head list; + int id; + unsigned int period_pos; + unsigned int buffer_pos; + bool is_stream_running; + struct task_struct *playback_task; + wait_queue_head_t playback_waitq; + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); +}; + +struct sound_adapter { + struct list_head dev_list; + struct most_interface *iface; + struct snd_card *card; + struct list_head list; + bool registered; + int pcm_dev_idx; +}; + +static struct list_head adpt_list; + +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ + SNDRV_PCM_INFO_MMAP_VALID | \ + SNDRV_PCM_INFO_BATCH | \ + SNDRV_PCM_INFO_INTERLEAVED | \ + SNDRV_PCM_INFO_BLOCK_TRANSFER) + +#define swap16(val) ( \ + (((u16)(val) << 8) & (u16)0xFF00) | \ + (((u16)(val) >> 8) & (u16)0x00FF)) + +#define swap32(val) ( \ + (((u32)(val) << 24) & (u32)0xFF000000) | \ + (((u32)(val) << 8) & (u32)0x00FF0000) | \ + (((u32)(val) >> 8) & (u32)0x0000FF00) | \ + (((u32)(val) >> 24) & (u32)0x000000FF)) + +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < (bytes / 2)) { + dest[i] = swap16(source[i]); + i++; + } +} + +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes - 2) { + dest[i] = source[i + 2]; + dest[i + 1] = source[i + 1]; + dest[i + 2] = source[i]; + i += 3; + } +} + +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes / 4) { + dest[i] = swap32(source[i]); + i++; + } +} + +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(most, alsa, bytes); +} + +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(most, alsa, bytes); +} + +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(most, alsa, bytes); +} + +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(most, alsa, bytes); +} + +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(alsa, most, bytes); +} + +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(alsa, most, bytes); +} + +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(alsa, most, bytes); +} + +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(alsa, most, bytes); +} + +/** + * get_channel - get pointer to channel + * @iface: interface structure + * @channel_id: channel ID + * + * This traverses the channel list and returns the channel matching the + * ID and interface. + * + * Returns pointer to channel on success or NULL otherwise. + */ +static struct channel *get_channel(struct most_interface *iface, + int channel_id) +{ + struct sound_adapter *adpt = iface->priv; + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { + if ((channel->iface == iface) && (channel->id == channel_id)) + return channel; + } + return NULL; +} + +/** + * copy_data - implements data copying function + * @channel: channel + * @mbo: MBO from core + * + * Copy data from/to ring buffer to/from MBO and update the buffer position + */ +static bool copy_data(struct channel *channel, struct mbo *mbo) +{ + struct snd_pcm_runtime *const runtime = channel->substream->runtime; + unsigned int const frame_bytes = channel->cfg->subbuffer_size; + unsigned int const buffer_size = runtime->buffer_size; + unsigned int frames; + unsigned int fr0; + + if (channel->cfg->direction & MOST_CH_RX) + frames = mbo->processed_length / frame_bytes; + else + frames = mbo->buffer_length / frame_bytes; + fr0 = min(buffer_size - channel->buffer_pos, frames); + + channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, + mbo->virt_address, + fr0 * frame_bytes); + + if (frames > fr0) { + /* wrap around at end of ring buffer */ + channel->copy_fn(runtime->dma_area, + mbo->virt_address + fr0 * frame_bytes, + (frames - fr0) * frame_bytes); + } + + channel->buffer_pos += frames; + if (channel->buffer_pos >= buffer_size) + channel->buffer_pos -= buffer_size; + channel->period_pos += frames; + if (channel->period_pos >= runtime->period_size) { + channel->period_pos -= runtime->period_size; + return true; + } + return false; +} + +/** + * playback_thread - function implements the playback thread + * @data: private data + * + * Thread which does the playback functionality in a loop. It waits for a free + * MBO from mostcore for a particular channel and copy the data from ring buffer + * to MBO. Submit the MBO back to mostcore, after copying the data. + * + * Returns 0 on success or error code otherwise. + */ +static int playback_thread(void *data) +{ + struct channel *const channel = data; + + while (!kthread_should_stop()) { + struct mbo *mbo = NULL; + bool period_elapsed = false; + + wait_event_interruptible( + channel->playback_waitq, + kthread_should_stop() || + (channel->is_stream_running && + (mbo = most_get_mbo(channel->iface, channel->id, + &comp)))); + if (!mbo) + continue; + + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + else + memset(mbo->virt_address, 0, mbo->buffer_length); + + most_submit_mbo(mbo); + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + } + return 0; +} + +/** + * pcm_open - implements open callback function for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is called when a PCM substream is opened. At least, the function should + * initialize the runtime->hw record. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_open(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + int ret; + + channel->substream = substream; + + if (cfg->direction == MOST_CH_TX) { + channel->playback_task = kthread_run(playback_thread, channel, + "most_audio_playback"); + if (IS_ERR(channel->playback_task)) { + pr_err("Couldn't start thread\n"); + return PTR_ERR(channel->playback_task); + } + } + + ret = most_start_channel(channel->iface, channel->id, &comp); + if (ret) { + pr_err("most_start_channel() failed!\n"); + if (cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + return ret; + } + + runtime->hw = channel->pcm_hardware; + return 0; +} + +/** + * pcm_close - implements close callback function for PCM middle layer + * @substream: sub-stream pointer + * + * Obviously, this is called when a PCM substream is closed. Any private + * instance for a PCM substream allocated in the open callback will be + * released here. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_close(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + if (channel->cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + most_stop_channel(channel->iface, channel->id, &comp); + return 0; +} + +/** + * pcm_prepare - implements prepare callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM is "prepared". Format rate, sample rate, + * etc., can be set here. This callback can be called many times at each setup. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_prepare(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + int width = snd_pcm_format_physical_width(runtime->format); + + channel->copy_fn = NULL; + + if (cfg->direction == MOST_CH_TX) { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = alsa_to_most_memcpy; + else if (width == 16) + channel->copy_fn = alsa_to_most_copy16; + else if (width == 24) + channel->copy_fn = alsa_to_most_copy24; + else if (width == 32) + channel->copy_fn = alsa_to_most_copy32; + } else { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = most_to_alsa_memcpy; + else if (width == 16) + channel->copy_fn = most_to_alsa_copy16; + else if (width == 24) + channel->copy_fn = most_to_alsa_copy24; + else if (width == 32) + channel->copy_fn = most_to_alsa_copy32; + } + + if (!channel->copy_fn) + return -EINVAL; + channel->period_pos = 0; + channel->buffer_pos = 0; + return 0; +} + +/** + * pcm_trigger - implements trigger callback function for PCM middle layer + * @substream: substream pointer + * @cmd: action to perform + * + * This is called when the PCM is started, stopped or paused. The action will be + * specified in the second argument, SNDRV_PCM_TRIGGER_XXX + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct channel *channel = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + channel->is_stream_running = true; + wake_up_interruptible(&channel->playback_waitq); + return 0; + + case SNDRV_PCM_TRIGGER_STOP: + channel->is_stream_running = false; + return 0; + + default: + return -EINVAL; + } + return 0; +} + +/** + * pcm_pointer - implements pointer callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM middle layer inquires the current + * hardware position on the buffer. The position must be returned in frames, + * ranging from 0 to buffer_size-1. + */ +static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + return channel->buffer_pos; +} + +/** + * Initialization of struct snd_pcm_ops + */ +static const struct snd_pcm_ops pcm_ops = { + .open = pcm_open, + .close = pcm_close, + .prepare = pcm_prepare, + .trigger = pcm_trigger, + .pointer = pcm_pointer, +}; + +static int split_arg_list(char *buf, u16 *ch_num, char **sample_res) +{ + char *num; + int ret; + + num = strsep(&buf, "x"); + if (!num) + goto err; + ret = kstrtou16(num, 0, ch_num); + if (ret) + goto err; + *sample_res = strsep(&buf, ".\n"); + if (!*sample_res) + goto err; + return 0; + +err: + pr_err("Bad PCM format\n"); + return -EINVAL; +} + +static const struct sample_resolution_info { + const char *sample_res; + int bytes; + u64 formats; +} sinfo[] = { + { "8", 1, SNDRV_PCM_FMTBIT_S8 }, + { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, + { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, + { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, +}; + +static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, + u16 ch_num, char *sample_res, + struct most_channel_config *cfg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sinfo); i++) { + if (!strcmp(sample_res, sinfo[i].sample_res)) + goto found; + } + pr_err("Unsupported PCM format\n"); + return -EINVAL; + +found: + if (!ch_num) { + pr_err("Bad number of channels\n"); + return -EINVAL; + } + + if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { + pr_err("Audio resolution doesn't fit subbuffer size\n"); + return -EINVAL; + } + + pcm_hw->info = MOST_PCM_INFO; + pcm_hw->rates = SNDRV_PCM_RATE_48000; + pcm_hw->rate_min = 48000; + pcm_hw->rate_max = 48000; + pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; + pcm_hw->period_bytes_min = cfg->buffer_size; + pcm_hw->period_bytes_max = cfg->buffer_size; + pcm_hw->periods_min = 1; + pcm_hw->periods_max = cfg->num_buffers; + pcm_hw->channels_min = ch_num; + pcm_hw->channels_max = ch_num; + pcm_hw->formats = sinfo[i].formats; + return 0; +} + +static void release_adapter(struct sound_adapter *adpt) +{ + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { + list_del(&channel->list); + kfree(channel); + } + if (adpt->card) + snd_card_free(adpt->card); + list_del(&adpt->list); + kfree(adpt); +} + +/** + * audio_probe_channel - probe function of the driver module + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * @cfg: pointer to actual channel configuration + * @arg_list: string that provides the name of the device to be created in /dev + * plus the desired audio resolution + * + * Creates sound card, pcm device, sets pcm ops and registers sound card. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_probe_channel(struct most_interface *iface, int channel_id, + struct most_channel_config *cfg, + char *device_name, char *arg_list) +{ + struct channel *channel; + struct sound_adapter *adpt; + struct snd_pcm *pcm; + int playback_count = 0; + int capture_count = 0; + int ret; + int direction; + u16 ch_num; + char *sample_res; + char arg_list_cpy[STRING_SIZE]; + + if (cfg->data_type != MOST_CH_SYNC) { + pr_err("Incompatible channel type\n"); + return -EINVAL; + } + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); + if (ret < 0) + return ret; + + list_for_each_entry(adpt, &adpt_list, list) { + if (adpt->iface != iface) + continue; + if (adpt->registered) + return -ENOSPC; + adpt->pcm_dev_idx++; + goto skip_adpt_alloc; + } + adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); + if (!adpt) + return -ENOMEM; + + adpt->iface = iface; + INIT_LIST_HEAD(&adpt->dev_list); + iface->priv = adpt; + list_add_tail(&adpt->list, &adpt_list); + ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, + sizeof(*channel), &adpt->card); + if (ret < 0) + goto err_free_adpt; + snprintf(adpt->card->driver, sizeof(adpt->card->driver), + "%s", DRIVER_NAME); + snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), + "Microchip INIC"); + snprintf(adpt->card->longname, sizeof(adpt->card->longname), + "%s at %s", adpt->card->shortname, iface->description); +skip_adpt_alloc: + if (get_channel(iface, channel_id)) { + pr_err("channel (%s:%d) is already linked\n", + iface->description, channel_id); + return -EEXIST; + } + + if (cfg->direction == MOST_CH_TX) { + playback_count = 1; + direction = SNDRV_PCM_STREAM_PLAYBACK; + } else { + capture_count = 1; + direction = SNDRV_PCM_STREAM_CAPTURE; + } + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) { + ret = -ENOMEM; + goto err_free_adpt; + } + channel->card = adpt->card; + channel->cfg = cfg; + channel->iface = iface; + channel->id = channel_id; + init_waitqueue_head(&channel->playback_waitq); + list_add_tail(&channel->list, &adpt->dev_list); + + ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, + cfg); + if (ret) + goto err_free_adpt; + + ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, + playback_count, capture_count, &pcm); + + if (ret < 0) + goto err_free_adpt; + + pcm->private_data = channel; + strscpy(pcm->name, device_name, sizeof(pcm->name)); + snd_pcm_set_ops(pcm, direction, &pcm_ops); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); + return 0; + +err_free_adpt: + release_adapter(adpt); + return ret; +} + +static int audio_create_sound_card(void) +{ + int ret; + struct sound_adapter *adpt; + + list_for_each_entry(adpt, &adpt_list, list) { + if (!adpt->registered) + goto adpt_alloc; + } + return -ENODEV; +adpt_alloc: + ret = snd_card_register(adpt->card); + if (ret < 0) { + release_adapter(adpt); + return ret; + } + adpt->registered = true; + return 0; +} + +/** + * audio_disconnect_channel - function to disconnect a channel + * @iface: pointer to interface instance + * @channel_id: channel index + * + * This frees allocated memory and removes the sound card from ALSA + * + * Returns 0 on success or error code otherwise. + */ +static int audio_disconnect_channel(struct most_interface *iface, + int channel_id) +{ + struct channel *channel; + struct sound_adapter *adpt = iface->priv; + + channel = get_channel(iface, channel_id); + if (!channel) + return -EINVAL; + + list_del(&channel->list); + + kfree(channel); + if (list_empty(&adpt->dev_list)) + release_adapter(adpt); + return 0; +} + +/** + * audio_rx_completion - completion handler for rx channels + * @mbo: pointer to buffer object that has completed + * + * This searches for the channel this MBO belongs to and copy the data from MBO + * to ring buffer + * + * Returns 0 on success or error code otherwise. + */ +static int audio_rx_completion(struct mbo *mbo) +{ + struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); + bool period_elapsed = false; + + if (!channel) + return -EINVAL; + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + most_put_mbo(mbo); + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + return 0; +} + +/** + * audio_tx_completion - completion handler for tx channels + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * + * This searches the channel that belongs to this combination of interface + * pointer and channel ID and wakes a process sitting in the wait queue of + * this channel. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_tx_completion(struct most_interface *iface, int channel_id) +{ + struct channel *channel = get_channel(iface, channel_id); + + if (!channel) + return -EINVAL; + + wake_up_interruptible(&channel->playback_waitq); + return 0; +} + +/** + * Initialization of the struct most_component + */ +static struct most_component comp = { + .mod = THIS_MODULE, + .name = DRIVER_NAME, + .probe_channel = audio_probe_channel, + .disconnect_channel = audio_disconnect_channel, + .rx_completion = audio_rx_completion, + .tx_completion = audio_tx_completion, + .cfg_complete = audio_create_sound_card, +}; + +static int __init audio_init(void) +{ + int ret; + + INIT_LIST_HEAD(&adpt_list); + + ret = most_register_component(&comp); + if (ret) { + pr_err("Failed to register %s\n", comp.name); + return ret; + } + ret = most_register_configfs_subsys(&comp); + if (ret) { + pr_err("Failed to register %s configfs subsys\n", comp.name); + most_deregister_component(&comp); + } + return ret; +} + +static void __exit audio_exit(void) +{ + most_deregister_configfs_subsys(&comp); + most_deregister_component(&comp); +} + +module_init(audio_init); +module_exit(audio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Gromm "); +MODULE_DESCRIPTION("Sound Component Module for Mostcore"); diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 535e6de..6f420cb 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -20,8 +20,6 @@ if MOST_COMPONENTS source "drivers/staging/most/net/Kconfig" -source "drivers/staging/most/sound/Kconfig" - source "drivers/staging/most/video/Kconfig" source "drivers/staging/most/dim2/Kconfig" diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index be94673..8b3fc5a 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MOST_NET) += net/ -obj-$(CONFIG_MOST_SOUND) += sound/ obj-$(CONFIG_MOST_VIDEO) += video/ obj-$(CONFIG_MOST_DIM2) += dim2/ obj-$(CONFIG_MOST_I2C) += i2c/ diff --git a/drivers/staging/most/sound/Kconfig b/drivers/staging/most/sound/Kconfig deleted file mode 100644 index ad9f782..0000000 --- a/drivers/staging/most/sound/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# MOST ALSA configuration -# - -config MOST_SOUND - tristate "Sound" - depends on SND - select SND_PCM - help - Say Y here if you want to commumicate via ALSA/sound devices. - - To compile this driver as a module, choose M here: the - module will be called most_sound. diff --git a/drivers/staging/most/sound/Makefile b/drivers/staging/most/sound/Makefile deleted file mode 100644 index f0cd9d8..0000000 --- a/drivers/staging/most/sound/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MOST_SOUND) += most_sound.o - -most_sound-objs := sound.o diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c deleted file mode 100644 index 8a449ab..0000000 --- a/drivers/staging/most/sound/sound.c +++ /dev/null @@ -1,753 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * sound.c - Sound component for Mostcore - * - * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "sound" -#define STRING_SIZE 80 - -static struct most_component comp; - -/** - * struct channel - private structure to keep channel specific data - * @substream: stores the substream structure - * @iface: interface for which the channel belongs to - * @cfg: channel configuration - * @card: registered sound card - * @list: list for private use - * @id: channel index - * @period_pos: current period position (ring buffer) - * @buffer_pos: current buffer position (ring buffer) - * @is_stream_running: identifies whether a stream is running or not - * @opened: set when the stream is opened - * @playback_task: playback thread - * @playback_waitq: waitq used by playback thread - */ -struct channel { - struct snd_pcm_substream *substream; - struct snd_pcm_hardware pcm_hardware; - struct most_interface *iface; - struct most_channel_config *cfg; - struct snd_card *card; - struct list_head list; - int id; - unsigned int period_pos; - unsigned int buffer_pos; - bool is_stream_running; - struct task_struct *playback_task; - wait_queue_head_t playback_waitq; - void (*copy_fn)(void *alsa, void *most, unsigned int bytes); -}; - -struct sound_adapter { - struct list_head dev_list; - struct most_interface *iface; - struct snd_card *card; - struct list_head list; - bool registered; - int pcm_dev_idx; -}; - -static struct list_head adpt_list; - -#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ - SNDRV_PCM_INFO_MMAP_VALID | \ - SNDRV_PCM_INFO_BATCH | \ - SNDRV_PCM_INFO_INTERLEAVED | \ - SNDRV_PCM_INFO_BLOCK_TRANSFER) - -#define swap16(val) ( \ - (((u16)(val) << 8) & (u16)0xFF00) | \ - (((u16)(val) >> 8) & (u16)0x00FF)) - -#define swap32(val) ( \ - (((u32)(val) << 24) & (u32)0xFF000000) | \ - (((u32)(val) << 8) & (u32)0x00FF0000) | \ - (((u32)(val) >> 8) & (u32)0x0000FF00) | \ - (((u32)(val) >> 24) & (u32)0x000000FF)) - -static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < (bytes / 2)) { - dest[i] = swap16(source[i]); - i++; - } -} - -static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < bytes - 2) { - dest[i] = source[i + 2]; - dest[i + 1] = source[i + 1]; - dest[i + 2] = source[i]; - i += 3; - } -} - -static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < bytes / 4) { - dest[i] = swap32(source[i]); - i++; - } -} - -static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) -{ - memcpy(most, alsa, bytes); -} - -static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) -{ - swap_copy16(most, alsa, bytes); -} - -static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) -{ - swap_copy24(most, alsa, bytes); -} - -static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) -{ - swap_copy32(most, alsa, bytes); -} - -static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) -{ - memcpy(alsa, most, bytes); -} - -static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) -{ - swap_copy16(alsa, most, bytes); -} - -static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) -{ - swap_copy24(alsa, most, bytes); -} - -static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) -{ - swap_copy32(alsa, most, bytes); -} - -/** - * get_channel - get pointer to channel - * @iface: interface structure - * @channel_id: channel ID - * - * This traverses the channel list and returns the channel matching the - * ID and interface. - * - * Returns pointer to channel on success or NULL otherwise. - */ -static struct channel *get_channel(struct most_interface *iface, - int channel_id) -{ - struct sound_adapter *adpt = iface->priv; - struct channel *channel, *tmp; - - list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { - if ((channel->iface == iface) && (channel->id == channel_id)) - return channel; - } - return NULL; -} - -/** - * copy_data - implements data copying function - * @channel: channel - * @mbo: MBO from core - * - * Copy data from/to ring buffer to/from MBO and update the buffer position - */ -static bool copy_data(struct channel *channel, struct mbo *mbo) -{ - struct snd_pcm_runtime *const runtime = channel->substream->runtime; - unsigned int const frame_bytes = channel->cfg->subbuffer_size; - unsigned int const buffer_size = runtime->buffer_size; - unsigned int frames; - unsigned int fr0; - - if (channel->cfg->direction & MOST_CH_RX) - frames = mbo->processed_length / frame_bytes; - else - frames = mbo->buffer_length / frame_bytes; - fr0 = min(buffer_size - channel->buffer_pos, frames); - - channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, - mbo->virt_address, - fr0 * frame_bytes); - - if (frames > fr0) { - /* wrap around at end of ring buffer */ - channel->copy_fn(runtime->dma_area, - mbo->virt_address + fr0 * frame_bytes, - (frames - fr0) * frame_bytes); - } - - channel->buffer_pos += frames; - if (channel->buffer_pos >= buffer_size) - channel->buffer_pos -= buffer_size; - channel->period_pos += frames; - if (channel->period_pos >= runtime->period_size) { - channel->period_pos -= runtime->period_size; - return true; - } - return false; -} - -/** - * playback_thread - function implements the playback thread - * @data: private data - * - * Thread which does the playback functionality in a loop. It waits for a free - * MBO from mostcore for a particular channel and copy the data from ring buffer - * to MBO. Submit the MBO back to mostcore, after copying the data. - * - * Returns 0 on success or error code otherwise. - */ -static int playback_thread(void *data) -{ - struct channel *const channel = data; - - while (!kthread_should_stop()) { - struct mbo *mbo = NULL; - bool period_elapsed = false; - - wait_event_interruptible( - channel->playback_waitq, - kthread_should_stop() || - (channel->is_stream_running && - (mbo = most_get_mbo(channel->iface, channel->id, - &comp)))); - if (!mbo) - continue; - - if (channel->is_stream_running) - period_elapsed = copy_data(channel, mbo); - else - memset(mbo->virt_address, 0, mbo->buffer_length); - - most_submit_mbo(mbo); - if (period_elapsed) - snd_pcm_period_elapsed(channel->substream); - } - return 0; -} - -/** - * pcm_open - implements open callback function for PCM middle layer - * @substream: pointer to ALSA PCM substream - * - * This is called when a PCM substream is opened. At least, the function should - * initialize the runtime->hw record. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_open(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct most_channel_config *cfg = channel->cfg; - int ret; - - channel->substream = substream; - - if (cfg->direction == MOST_CH_TX) { - channel->playback_task = kthread_run(playback_thread, channel, - "most_audio_playback"); - if (IS_ERR(channel->playback_task)) { - pr_err("Couldn't start thread\n"); - return PTR_ERR(channel->playback_task); - } - } - - ret = most_start_channel(channel->iface, channel->id, &comp); - if (ret) { - pr_err("most_start_channel() failed!\n"); - if (cfg->direction == MOST_CH_TX) - kthread_stop(channel->playback_task); - return ret; - } - - runtime->hw = channel->pcm_hardware; - return 0; -} - -/** - * pcm_close - implements close callback function for PCM middle layer - * @substream: sub-stream pointer - * - * Obviously, this is called when a PCM substream is closed. Any private - * instance for a PCM substream allocated in the open callback will be - * released here. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_close(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - - if (channel->cfg->direction == MOST_CH_TX) - kthread_stop(channel->playback_task); - most_stop_channel(channel->iface, channel->id, &comp); - return 0; -} - -/** - * pcm_prepare - implements prepare callback function for PCM middle layer - * @substream: substream pointer - * - * This callback is called when the PCM is "prepared". Format rate, sample rate, - * etc., can be set here. This callback can be called many times at each setup. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_prepare(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct most_channel_config *cfg = channel->cfg; - int width = snd_pcm_format_physical_width(runtime->format); - - channel->copy_fn = NULL; - - if (cfg->direction == MOST_CH_TX) { - if (snd_pcm_format_big_endian(runtime->format) || width == 8) - channel->copy_fn = alsa_to_most_memcpy; - else if (width == 16) - channel->copy_fn = alsa_to_most_copy16; - else if (width == 24) - channel->copy_fn = alsa_to_most_copy24; - else if (width == 32) - channel->copy_fn = alsa_to_most_copy32; - } else { - if (snd_pcm_format_big_endian(runtime->format) || width == 8) - channel->copy_fn = most_to_alsa_memcpy; - else if (width == 16) - channel->copy_fn = most_to_alsa_copy16; - else if (width == 24) - channel->copy_fn = most_to_alsa_copy24; - else if (width == 32) - channel->copy_fn = most_to_alsa_copy32; - } - - if (!channel->copy_fn) - return -EINVAL; - channel->period_pos = 0; - channel->buffer_pos = 0; - return 0; -} - -/** - * pcm_trigger - implements trigger callback function for PCM middle layer - * @substream: substream pointer - * @cmd: action to perform - * - * This is called when the PCM is started, stopped or paused. The action will be - * specified in the second argument, SNDRV_PCM_TRIGGER_XXX - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct channel *channel = substream->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - channel->is_stream_running = true; - wake_up_interruptible(&channel->playback_waitq); - return 0; - - case SNDRV_PCM_TRIGGER_STOP: - channel->is_stream_running = false; - return 0; - - default: - return -EINVAL; - } - return 0; -} - -/** - * pcm_pointer - implements pointer callback function for PCM middle layer - * @substream: substream pointer - * - * This callback is called when the PCM middle layer inquires the current - * hardware position on the buffer. The position must be returned in frames, - * ranging from 0 to buffer_size-1. - */ -static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - - return channel->buffer_pos; -} - -/** - * Initialization of struct snd_pcm_ops - */ -static const struct snd_pcm_ops pcm_ops = { - .open = pcm_open, - .close = pcm_close, - .prepare = pcm_prepare, - .trigger = pcm_trigger, - .pointer = pcm_pointer, -}; - -static int split_arg_list(char *buf, u16 *ch_num, char **sample_res) -{ - char *num; - int ret; - - num = strsep(&buf, "x"); - if (!num) - goto err; - ret = kstrtou16(num, 0, ch_num); - if (ret) - goto err; - *sample_res = strsep(&buf, ".\n"); - if (!*sample_res) - goto err; - return 0; - -err: - pr_err("Bad PCM format\n"); - return -EINVAL; -} - -static const struct sample_resolution_info { - const char *sample_res; - int bytes; - u64 formats; -} sinfo[] = { - { "8", 1, SNDRV_PCM_FMTBIT_S8 }, - { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, - { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, - { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, -}; - -static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, - u16 ch_num, char *sample_res, - struct most_channel_config *cfg) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sinfo); i++) { - if (!strcmp(sample_res, sinfo[i].sample_res)) - goto found; - } - pr_err("Unsupported PCM format\n"); - return -EINVAL; - -found: - if (!ch_num) { - pr_err("Bad number of channels\n"); - return -EINVAL; - } - - if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { - pr_err("Audio resolution doesn't fit subbuffer size\n"); - return -EINVAL; - } - - pcm_hw->info = MOST_PCM_INFO; - pcm_hw->rates = SNDRV_PCM_RATE_48000; - pcm_hw->rate_min = 48000; - pcm_hw->rate_max = 48000; - pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; - pcm_hw->period_bytes_min = cfg->buffer_size; - pcm_hw->period_bytes_max = cfg->buffer_size; - pcm_hw->periods_min = 1; - pcm_hw->periods_max = cfg->num_buffers; - pcm_hw->channels_min = ch_num; - pcm_hw->channels_max = ch_num; - pcm_hw->formats = sinfo[i].formats; - return 0; -} - -static void release_adapter(struct sound_adapter *adpt) -{ - struct channel *channel, *tmp; - - list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { - list_del(&channel->list); - kfree(channel); - } - if (adpt->card) - snd_card_free(adpt->card); - list_del(&adpt->list); - kfree(adpt); -} - -/** - * audio_probe_channel - probe function of the driver module - * @iface: pointer to interface instance - * @channel_id: channel index/ID - * @cfg: pointer to actual channel configuration - * @arg_list: string that provides the name of the device to be created in /dev - * plus the desired audio resolution - * - * Creates sound card, pcm device, sets pcm ops and registers sound card. - * - * Returns 0 on success or error code otherwise. - */ -static int audio_probe_channel(struct most_interface *iface, int channel_id, - struct most_channel_config *cfg, - char *device_name, char *arg_list) -{ - struct channel *channel; - struct sound_adapter *adpt; - struct snd_pcm *pcm; - int playback_count = 0; - int capture_count = 0; - int ret; - int direction; - u16 ch_num; - char *sample_res; - char arg_list_cpy[STRING_SIZE]; - - if (cfg->data_type != MOST_CH_SYNC) { - pr_err("Incompatible channel type\n"); - return -EINVAL; - } - strlcpy(arg_list_cpy, arg_list, STRING_SIZE); - ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); - if (ret < 0) - return ret; - - list_for_each_entry(adpt, &adpt_list, list) { - if (adpt->iface != iface) - continue; - if (adpt->registered) - return -ENOSPC; - adpt->pcm_dev_idx++; - goto skip_adpt_alloc; - } - adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); - if (!adpt) - return -ENOMEM; - - adpt->iface = iface; - INIT_LIST_HEAD(&adpt->dev_list); - iface->priv = adpt; - list_add_tail(&adpt->list, &adpt_list); - ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, - sizeof(*channel), &adpt->card); - if (ret < 0) - goto err_free_adpt; - snprintf(adpt->card->driver, sizeof(adpt->card->driver), - "%s", DRIVER_NAME); - snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), - "Microchip INIC"); - snprintf(adpt->card->longname, sizeof(adpt->card->longname), - "%s at %s", adpt->card->shortname, iface->description); -skip_adpt_alloc: - if (get_channel(iface, channel_id)) { - pr_err("channel (%s:%d) is already linked\n", - iface->description, channel_id); - return -EEXIST; - } - - if (cfg->direction == MOST_CH_TX) { - playback_count = 1; - direction = SNDRV_PCM_STREAM_PLAYBACK; - } else { - capture_count = 1; - direction = SNDRV_PCM_STREAM_CAPTURE; - } - channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (!channel) { - ret = -ENOMEM; - goto err_free_adpt; - } - channel->card = adpt->card; - channel->cfg = cfg; - channel->iface = iface; - channel->id = channel_id; - init_waitqueue_head(&channel->playback_waitq); - list_add_tail(&channel->list, &adpt->dev_list); - - ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, - cfg); - if (ret) - goto err_free_adpt; - - ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, - playback_count, capture_count, &pcm); - - if (ret < 0) - goto err_free_adpt; - - pcm->private_data = channel; - strscpy(pcm->name, device_name, sizeof(pcm->name)); - snd_pcm_set_ops(pcm, direction, &pcm_ops); - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); - return 0; - -err_free_adpt: - release_adapter(adpt); - return ret; -} - -static int audio_create_sound_card(void) -{ - int ret; - struct sound_adapter *adpt; - - list_for_each_entry(adpt, &adpt_list, list) { - if (!adpt->registered) - goto adpt_alloc; - } - return -ENODEV; -adpt_alloc: - ret = snd_card_register(adpt->card); - if (ret < 0) { - release_adapter(adpt); - return ret; - } - adpt->registered = true; - return 0; -} - -/** - * audio_disconnect_channel - function to disconnect a channel - * @iface: pointer to interface instance - * @channel_id: channel index - * - * This frees allocated memory and removes the sound card from ALSA - * - * Returns 0 on success or error code otherwise. - */ -static int audio_disconnect_channel(struct most_interface *iface, - int channel_id) -{ - struct channel *channel; - struct sound_adapter *adpt = iface->priv; - - channel = get_channel(iface, channel_id); - if (!channel) - return -EINVAL; - - list_del(&channel->list); - - kfree(channel); - if (list_empty(&adpt->dev_list)) - release_adapter(adpt); - return 0; -} - -/** - * audio_rx_completion - completion handler for rx channels - * @mbo: pointer to buffer object that has completed - * - * This searches for the channel this MBO belongs to and copy the data from MBO - * to ring buffer - * - * Returns 0 on success or error code otherwise. - */ -static int audio_rx_completion(struct mbo *mbo) -{ - struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); - bool period_elapsed = false; - - if (!channel) - return -EINVAL; - if (channel->is_stream_running) - period_elapsed = copy_data(channel, mbo); - most_put_mbo(mbo); - if (period_elapsed) - snd_pcm_period_elapsed(channel->substream); - return 0; -} - -/** - * audio_tx_completion - completion handler for tx channels - * @iface: pointer to interface instance - * @channel_id: channel index/ID - * - * This searches the channel that belongs to this combination of interface - * pointer and channel ID and wakes a process sitting in the wait queue of - * this channel. - * - * Returns 0 on success or error code otherwise. - */ -static int audio_tx_completion(struct most_interface *iface, int channel_id) -{ - struct channel *channel = get_channel(iface, channel_id); - - if (!channel) - return -EINVAL; - - wake_up_interruptible(&channel->playback_waitq); - return 0; -} - -/** - * Initialization of the struct most_component - */ -static struct most_component comp = { - .mod = THIS_MODULE, - .name = DRIVER_NAME, - .probe_channel = audio_probe_channel, - .disconnect_channel = audio_disconnect_channel, - .rx_completion = audio_rx_completion, - .tx_completion = audio_tx_completion, - .cfg_complete = audio_create_sound_card, -}; - -static int __init audio_init(void) -{ - int ret; - - INIT_LIST_HEAD(&adpt_list); - - ret = most_register_component(&comp); - if (ret) { - pr_err("Failed to register %s\n", comp.name); - return ret; - } - ret = most_register_configfs_subsys(&comp); - if (ret) { - pr_err("Failed to register %s configfs subsys\n", comp.name); - most_deregister_component(&comp); - } - return ret; -} - -static void __exit audio_exit(void) -{ - most_deregister_configfs_subsys(&comp); - most_deregister_component(&comp); -} - -module_init(audio_init); -module_exit(audio_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Christian Gromm "); -MODULE_DESCRIPTION("Sound Component Module for Mostcore"); -- 2.7.4 From dan.carpenter at oracle.com Mon Nov 2 15:12:36 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Mon, 2 Nov 2020 18:12:36 +0300 Subject: [PATCH -next] media: cedrus: fix reference leak in cedrus_start_streaming In-Reply-To: <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> References: <20201102142622.140001-1-zhangqilong3@huawei.com> <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> Message-ID: <20201102151236.GD12347@kadam> On Mon, Nov 02, 2020 at 03:18:38PM +0100, Maxime Ripard wrote: > On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: > > pm_runtime_get_sync will increment pm usage counter even it > > failed. Forgetting to pm_runtime_put_noidle will result in > > reference leak in cedrus_start_streaming. We should fix it. > > > > Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") > > Signed-off-by: Zhang Qilong > > Shouldn't we fix pm_runtime_get_sync instead then? It seems that most of > the callers get this wrong, and that's definitely non-obvious. > > Maxime The other bug that people run into is that pm_runtime_get_sync() can return 1 on success. drivers/spi/spi-img-spfi.c:734 img_spfi_resume() warn: pm_runtime_get_sync() also returns 1 on success drivers/mfd/arizona-core.c:49 arizona_clk32k_enable() warn: pm_runtime_get_sync() also returns 1 on success drivers/usb/dwc3/dwc3-pci.c:212 dwc3_pci_resume_work() warn: pm_runtime_get_sync() also returns 1 on success drivers/input/keyboard/omap4-keypad.c:279 omap4_keypad_probe() warn: pm_runtime_get_sync() also returns 1 on success drivers/gpu/drm/vc4/vc4_dsi.c:839 vc4_dsi_encoder_enable() warn: pm_runtime_get_sync() also returns 1 on success drivers/gpu/drm/i915/selftests/mock_gem_device.c:157 mock_gem_device() warn: 'pm_runtime_get_sync(&pdev->dev)' returns positive and negative drivers/watchdog/rti_wdt.c:230 rti_wdt_probe() warn: pm_runtime_get_sync() also returns 1 on success drivers/media/platform/exynos4-is/mipi-csis.c:513 s5pcsis_s_stream() warn: pm_runtime_get_sync() also returns 1 on success drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c:89 mtk_vcodec_dec_pw_on() warn: pm_runtime_get_sync() also returns 1 on success drivers/media/platform/ti-vpe/cal.c:794 cal_probe() warn: pm_runtime_get_sync() also returns 1 on success drivers/media/platform/ti-vpe/vpe.c:2478 vpe_runtime_get() warn: pm_runtime_get_sync() also returns 1 on success drivers/media/i2c/smiapp/smiapp-core.c:1529 smiapp_pm_get_init() warn: pm_runtime_get_sync() also returns 1 on success I don't really understand the point of incrementing the counter on failure well enough to write a check for this... regards, dan carpenter From gregkh at linuxfoundation.org Mon Nov 2 15:31:45 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Mon, 2 Nov 2020 16:31:45 +0100 Subject: [PATCH] drivers: most: add ALSA sound driver In-Reply-To: <1604330043-5517-1-git-send-email-christian.gromm@microchip.com> References: <1604330043-5517-1-git-send-email-christian.gromm@microchip.com> Message-ID: <20201102153145.GA1034326@kroah.com> On Mon, Nov 02, 2020 at 04:14:03PM +0100, Christian Gromm wrote: > This patch moves the ALSA sound driver out of the staging area and adds it > to the stable part of the MOST driver. Modifications to the Makefiles and > Kconfigs are done accordingly to not break the build. > > Signed-off-by: Christian Gromm > --- > drivers/most/Kconfig | 10 + > drivers/most/Makefile | 1 + > drivers/most/most_snd.c | 753 ++++++++++++++++++++++++++++++++++++ > drivers/staging/most/Kconfig | 2 - > drivers/staging/most/Makefile | 1 - > drivers/staging/most/sound/Kconfig | 14 - > drivers/staging/most/sound/Makefile | 4 - > drivers/staging/most/sound/sound.c | 753 ------------------------------------ > 8 files changed, 764 insertions(+), 774 deletions(-) > create mode 100644 drivers/most/most_snd.c > delete mode 100644 drivers/staging/most/sound/Kconfig > delete mode 100644 drivers/staging/most/sound/Makefile > delete mode 100644 drivers/staging/most/sound/sound.c > > diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig > index ebfe84e..4b8145b 100644 > --- a/drivers/most/Kconfig > +++ b/drivers/most/Kconfig > @@ -32,4 +32,14 @@ config MOST_CDEV > > To compile this driver as a module, choose M here: the > module will be called most_cdev. > + > +config MOST_SND > + tristate "Sound" > + depends on SND > + select SND_PCM > + help > + Say Y here if you want to commumicate via ALSA/sound devices. > + > + To compile this driver as a module, choose M here: the > + module will be called most_sound. > endif > diff --git a/drivers/most/Makefile b/drivers/most/Makefile > index 8b53ca4..60db6cd 100644 > --- a/drivers/most/Makefile > +++ b/drivers/most/Makefile > @@ -5,3 +5,4 @@ most_core-y := core.o \ > > obj-$(CONFIG_MOST_USB_HDM) += most_usb.o > obj-$(CONFIG_MOST_CDEV) += most_cdev.o > +obj-$(CONFIG_MOST_SND) += most_snd.o > diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c > new file mode 100644 > index 0000000..8a449ab > --- /dev/null > +++ b/drivers/most/most_snd.c > @@ -0,0 +1,753 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * sound.c - Sound component for Mostcore > + * > + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG > + */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define DRIVER_NAME "sound" > +#define STRING_SIZE 80 > + > +static struct most_component comp; > + > +/** > + * struct channel - private structure to keep channel specific data > + * @substream: stores the substream structure > + * @iface: interface for which the channel belongs to > + * @cfg: channel configuration > + * @card: registered sound card > + * @list: list for private use > + * @id: channel index > + * @period_pos: current period position (ring buffer) > + * @buffer_pos: current buffer position (ring buffer) > + * @is_stream_running: identifies whether a stream is running or not > + * @opened: set when the stream is opened > + * @playback_task: playback thread > + * @playback_waitq: waitq used by playback thread > + */ > +struct channel { > + struct snd_pcm_substream *substream; > + struct snd_pcm_hardware pcm_hardware; > + struct most_interface *iface; > + struct most_channel_config *cfg; > + struct snd_card *card; > + struct list_head list; > + int id; > + unsigned int period_pos; > + unsigned int buffer_pos; > + bool is_stream_running; > + struct task_struct *playback_task; > + wait_queue_head_t playback_waitq; > + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); > +}; > + > +struct sound_adapter { > + struct list_head dev_list; > + struct most_interface *iface; > + struct snd_card *card; > + struct list_head list; > + bool registered; > + int pcm_dev_idx; > +}; > + > +static struct list_head adpt_list; > + > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > + SNDRV_PCM_INFO_MMAP_VALID | \ > + SNDRV_PCM_INFO_BATCH | \ > + SNDRV_PCM_INFO_INTERLEAVED | \ > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > + > +#define swap16(val) ( \ > + (((u16)(val) << 8) & (u16)0xFF00) | \ > + (((u16)(val) >> 8) & (u16)0x00FF)) > + > +#define swap32(val) ( \ > + (((u32)(val) << 24) & (u32)0xFF000000) | \ > + (((u32)(val) << 8) & (u32)0x00FF0000) | \ > + (((u32)(val) >> 8) & (u32)0x0000FF00) | \ > + (((u32)(val) >> 24) & (u32)0x000000FF)) Doesn't swab16() and swab32() work for this? I don't think you need to reimplement these. > + > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < (bytes / 2)) { > + dest[i] = swap16(source[i]); > + i++; > + } > +} > + > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < bytes - 2) { > + dest[i] = source[i + 2]; > + dest[i + 1] = source[i + 1]; > + dest[i + 2] = source[i]; > + i += 3; > + } > +} > + > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < bytes / 4) { > + dest[i] = swap32(source[i]); > + i++; > + } > +} Same for the above, don't we have functions for this? thanks, greg k-h From kvalo at codeaurora.org Mon Nov 2 15:58:11 2020 From: kvalo at codeaurora.org (Kalle Valo) Date: Mon, 02 Nov 2020 17:58:11 +0200 Subject: [PATCH 01/23] dt-bindings: introduce silabs,wfx.yaml In-Reply-To: <3929101.dIHeVNgAIR@pc-42> (=?utf-8?B?IkrDqXLDtG1l?= Pouiller"'s message of "Wed, 14 Oct 2020 15:49:12 +0200") References: <20201012104648.985256-1-Jerome.Pouiller@silabs.com> <20201012104648.985256-2-Jerome.Pouiller@silabs.com> <20201013164935.GA3646933@bogus> <3929101.dIHeVNgAIR@pc-42> Message-ID: <87imanpx7w.fsf@codeaurora.org> J?r?me Pouiller writes: > On Tuesday 13 October 2020 18:49:35 CEST Rob Herring wrote: >> On Mon, Oct 12, 2020 at 12:46:26PM +0200, Jerome Pouiller wrote: >> > From: J?r?me Pouiller > [...] >> > + Note that in add of the properties below, the WFx driver also supports >> > + `mac-address` and `local-mac-address` as described in >> > + Documentation/devicetree/bindings/net/ethernet.txt >> >> Note what ethernet.txt contains... This should have a $ref to >> ethernet-controller.yaml to express the above. >> >> You can add 'mac-address: true' if you want to be explicit about what >> properties are used. > > Here, only mac-address and local-mac-address are supported. So, would the > code below do the job? > > local-mac-address: > $ref: ethernet-controller.yaml#/properties/local-mac-address > > mac-address: > $ref: ethernet-controller.yaml#/properties/mac-address > > > [...] >> > + spi-max-frequency: >> > + description: (SPI only) Maximum SPI clocking speed of device in Hz. >> >> No need to redefine a common property. > > When a property is specific to a bus, I would have like to explicitly > say it. That's why I redefined the description. > > > [...] >> > + config-file: >> > + description: Use an alternative file as PDS. Default is `wf200.pds`. Only >> > + necessary for development/debug purpose. >> >> 'firmware-name' is typically what we'd use here. Though if just for >> debug/dev, perhaps do a debugfs interface for this instead. As DT should >> come from the firmware/bootloader, requiring changing the DT for >> dev/debug is not the easiest workflow compared to doing something from >> userspace. > > This file is not a firmware. It mainly contains data related to the > antenna. At the beginning, this property has been added for > development. With the time, I think it can be used to have one disk > image for several devices that differ only in antenna. > > I am going to remove the part about development/debug purpose. config-file doesn't sound right either. So what kind of data is this, calibration data or what? -- https://patchwork.kernel.org/project/linux-wireless/list/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches From kvalo at codeaurora.org Mon Nov 2 16:02:22 2020 From: kvalo at codeaurora.org (Kalle Valo) Date: Mon, 02 Nov 2020 18:02:22 +0200 Subject: [PATCH 07/23] wfx: add bus_sdio.c In-Reply-To: (Ulf Hansson's message of "Fri, 16 Oct 2020 13:54:48 +0200") References: <20201012104648.985256-1-Jerome.Pouiller@silabs.com> <2628294.9EgBEFZmRI@pc-42> <20201014124334.lgx53qvtgkmfkepc@pali> <2444203.ROLCPKctRj@pc-42> Message-ID: <87eelbpx0x.fsf@codeaurora.org> Ulf Hansson writes: > On Thu, 15 Oct 2020 at 16:03, J?r?me Pouiller > wrote: >> >> On Wednesday 14 October 2020 14:43:34 CEST Pali Roh?r wrote: >> > On Wednesday 14 October 2020 13:52:15 J?r?me Pouiller wrote: >> > > On Tuesday 13 October 2020 22:11:56 CEST Pali Roh?r wrote: >> > > > On Monday 12 October 2020 12:46:32 Jerome Pouiller wrote: >> > > > > +#define SDIO_VENDOR_ID_SILABS 0x0000 >> > > > > +#define SDIO_DEVICE_ID_SILABS_WF200 0x1000 >> > > > > +static const struct sdio_device_id wfx_sdio_ids[] = { >> > > > > + { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) }, >> > > > >> > > > Please move ids into common include file include/linux/mmc/sdio_ids.h >> > > > where are all SDIO ids. Now all drivers have ids defined in that file. >> > > > >> > > > > + // FIXME: ignore VID/PID and only rely on device tree >> > > > > + // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, >> > > > >> > > > What is the reason for ignoring vendor and device ids? >> > > >> > > The device has a particularity, its VID/PID is 0000:1000 (as you can see >> > > above). This value is weird. The risk of collision with another device is >> > > high. >> > >> > Those ids looks strange. You are from Silabs, can you check internally >> > in Silabs if ids are really correct? And which sdio vendor id you in >> > Silabs got assigned for your products? >> >> I confirm these ids are the ones burned in the WF200. We have to deal with >> that :( . > > Yep. Unfortunately this isn't so uncommon when targeting the embedded > types of devices. > > The good thing is, that we already have bindings allowing us to specify this. > >> >> >> > I know that sdio devices with multiple functions may have different sdio >> > vendor/device id particular function and in common CIS (function 0). >> > >> > Could not be a problem that on one place is vendor/device id correct and >> > on other place is that strange value? >> > >> > I have sent following patch (now part of upstream kernel) which exports >> > these ids to userspace: >> > https://lore.kernel.org/linux-mmc/20200527110858.17504-2-pali at kernel.org/T/#u >> > >> > Also for debugging ids and information about sdio cards, I sent another >> > patch which export additional data: >> > https://lore.kernel.org/linux-mmc/20200727133837.19086-1-pali at kernel.org/T/#u >> > >> > Could you try them and look at /sys/class/mmc_host/ attribute outputs? >> >> Here is: >> >> # cd /sys/class/mmc_host/ && grep -r . mmc1/ >> mmc1/power/runtime_suspended_time:0 >> grep: mmc1/power/autosuspend_delay_ms: Input/output error >> mmc1/power/runtime_active_time:0 >> mmc1/power/control:auto >> mmc1/power/runtime_status:unsupported >> mmc1/mmc1:0001/vendor:0x0000 >> mmc1/mmc1:0001/rca:0x0001 >> mmc1/mmc1:0001/device:0x1000 >> mmc1/mmc1:0001/mmc1:0001:1/vendor:0x0000 >> mmc1/mmc1:0001/mmc1:0001:1/device:0x1000 >> grep: mmc1/mmc1:0001/mmc1:0001:1/info4: No data available >> mmc1/mmc1:0001/mmc1:0001:1/power/runtime_suspended_time:0 >> grep: mmc1/mmc1:0001/mmc1:0001:1/power/autosuspend_delay_ms: Input/output error >> mmc1/mmc1:0001/mmc1:0001:1/power/runtime_active_time:0 >> mmc1/mmc1:0001/mmc1:0001:1/power/control:auto >> mmc1/mmc1:0001/mmc1:0001:1/power/runtime_status:unsupported >> mmc1/mmc1:0001/mmc1:0001:1/class:0x00 >> grep: mmc1/mmc1:0001/mmc1:0001:1/info2: No data available >> mmc1/mmc1:0001/mmc1:0001:1/modalias:sdio:c00v0000d1000 >> mmc1/mmc1:0001/mmc1:0001:1/revision:0.0 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_NAME=mmc >> mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_FULLNAME=/soc/sdhci at 7e300000/mmc at 1 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_0=silabs,wfx-sdio >> mmc1/mmc1:0001/mmc1:0001:1/uevent:OF_COMPATIBLE_N=1 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_CLASS=00 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_ID=0000:1000 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:SDIO_REVISION=0.0 >> mmc1/mmc1:0001/mmc1:0001:1/uevent:MODALIAS=sdio:c00v0000d1000 >> grep: mmc1/mmc1:0001/mmc1:0001:1/info3: No data available >> grep: mmc1/mmc1:0001/mmc1:0001:1/info1: No data available >> mmc1/mmc1:0001/ocr:0x00200000 >> grep: mmc1/mmc1:0001/info4: No data available >> mmc1/mmc1:0001/power/runtime_suspended_time:0 >> grep: mmc1/mmc1:0001/power/autosuspend_delay_ms: Input/output error >> mmc1/mmc1:0001/power/runtime_active_time:0 >> mmc1/mmc1:0001/power/control:auto >> mmc1/mmc1:0001/power/runtime_status:unsupported >> grep: mmc1/mmc1:0001/info2: No data available >> mmc1/mmc1:0001/type:SDIO >> mmc1/mmc1:0001/revision:0.0 >> mmc1/mmc1:0001/uevent:MMC_TYPE=SDIO >> mmc1/mmc1:0001/uevent:SDIO_ID=0000:1000 >> mmc1/mmc1:0001/uevent:SDIO_REVISION=0.0 >> grep: mmc1/mmc1:0001/info3: No data available >> grep: mmc1/mmc1:0001/info1: No data available >> >> > > Please have a look at the > Documentation/devicetree/bindings/mmc/mmc-controller.yaml, there you > find that from a child node of the mmc host's node, we can specify an > embedded SDIO functional device. > > In sdio_add_func(), which calls sdio_set_of_node() - we assign the > func->dev.of_node its corresponding child node for the SDIO func. > Allowing the sdio functional driver to be matched with the SDIO func > device. > > Perhaps what is missing, is that we may want to avoid probing an > in-correct sdio driver, based upon buggy SDIO ids. I don't think we > take some actions in the mmc core to prevent this, but maybe it's not > a big problem anyway. > > When it comes to documenting the buggy SDIO ids, please add some > information about this in the common SDIO headers. It's nice to have a > that information, if any issue comes up later on. And if there's some special setup (DT etc) needed to get the wireless driver working that should be documented in the driver side as well. The expectation is that an upstream driver is just plug and play, and if it's not there should be clear documentation how to enable the driver. -- https://patchwork.kernel.org/project/linux-wireless/list/ https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches From siddhantgupta416 at gmail.com Mon Nov 2 19:34:02 2020 From: siddhantgupta416 at gmail.com (siddhant gupta(siddhant1223)) Date: Tue, 3 Nov 2020 01:04:02 +0530 Subject: [PATCH] staging: mt7621-dma: Prefer Using BIT Macro instead of left shifting on 1. Message-ID: <20201102193402.GA14965@Sleakybeast> Replace left shifting on 1 by a BIT macro to fix checkpatch warning. Signed-off-by: Siddhant Gupta --- drivers/staging/mt7621-dma/mtk-hsdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c index 354536783e1c..a9e1a1b14035 100644 --- a/drivers/staging/mt7621-dma/mtk-hsdma.c +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c @@ -72,7 +72,7 @@ #define HSDMA_GLO_TX_DMA BIT(0) #define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) -#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) +#define HSDMA_BT_SIZE_32BYTES BIT(HSDMA_GLO_BT_SHIFT) #define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) #define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) -- 2.25.1 From gregkh at linuxfoundation.org Mon Nov 2 19:40:55 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Mon, 2 Nov 2020 20:40:55 +0100 Subject: [PATCH] staging: mt7621-dma: Prefer Using BIT Macro instead of left shifting on 1. In-Reply-To: <20201102193402.GA14965@Sleakybeast> References: <20201102193402.GA14965@Sleakybeast> Message-ID: <20201102194055.GA2429929@kroah.com> On Tue, Nov 03, 2020 at 01:04:02AM +0530, siddhant gupta(siddhant1223) wrote: > > Replace left shifting on 1 by a BIT macro to fix checkpatch warning. > > Signed-off-by: Siddhant Gupta > > --- > drivers/staging/mt7621-dma/mtk-hsdma.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c > index 354536783e1c..a9e1a1b14035 100644 > --- a/drivers/staging/mt7621-dma/mtk-hsdma.c > +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c > @@ -72,7 +72,7 @@ > #define HSDMA_GLO_TX_DMA BIT(0) > > #define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) > -#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) > +#define HSDMA_BT_SIZE_32BYTES BIT(HSDMA_GLO_BT_SHIFT) > #define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) > #define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) In looking at the code, does this change really make sense? (hint, I don't think so...) From bokeefe at alum.wpi.edu Mon Nov 2 15:08:49 2020 From: bokeefe at alum.wpi.edu (Brian O'Keefe) Date: Mon, 2 Nov 2020 10:08:49 -0500 Subject: [PATCH] staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids In-Reply-To: References: Message-ID: On Fri, Oct 30, 2020 at 10:25 AM Arend Van Spriel wrote: > > On 10/29/2020 2:52 PM, Brian O'Keefe wrote: > > Add 024c:0627 to the list of SDIO device-ids, based on hardware found in > > the wild. This hardware exists on at least some Acer SW1-011 tablets. > > > > Signed-off-by: Brian O'Keefe > > --- > > drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > index 5b1392deb0a7..7256d55fcc1b 100644 > > --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > @@ -21,6 +21,7 @@ static const struct sdio_device_id sdio_ids[] = > > { SDIO_DEVICE(0x024c, 0x0525), }, > > { SDIO_DEVICE(0x024c, 0x0623), }, > > { SDIO_DEVICE(0x024c, 0x0626), }, > > + { SDIO_DEVICE(0x024c, 0x0627), }, > > { SDIO_DEVICE(0x024c, 0xb723), }, > > shouldn't these be listed in include/linux/mmc/sdio_ids.h ? It certainly looks that way; this was the only place that used hex values in the SDIO_DEVICE macro directly. I'm happy to submit a follow-up patch to create constants in sdio_ids.h and use those instead. > > Regards, > Arend From sergio.paracuellos at gmail.com Mon Nov 2 20:25:15 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 2 Nov 2020 21:25:15 +0100 Subject: [PATCH] staging: mt7621-pci: avoid to request pci bus resources Message-ID: <20201102202515.19073-1-sergio.paracuellos@gmail.com> After upgrading kernel to version 5.9.x the driver was not working anymore showing the following kernel trace: ... mt7621-pci 1e140000.pcie: resource collision: [mem 0x60000000-0x6fffffff] conflicts with pcie at 1e140000 [mem 0x60000000-0x6fffffff] ------------[ cut here ]------------ WARNING: CPU: 2 PID: 73 at kernel/resource.c:1400 devm_request_resource+0xfc/0x10c Modules linked in: CPU: 2 PID: 73 Comm: kworker/2:1 Not tainted 5.9.2 #0 Workqueue: events deferred_probe_work_func Stack : 00000000 81590000 807d0a1c 808a0000 8fd49080 807d0000 00000009 808ac820 00000001 808338d0 7fff0001 800839dc 00000049 00000001 8fe51b00 367204ab 00000000 00000000 807d0a1c 807c0000 00000001 80082358 8fe50000 00559000 00000000 8fe519f1 ffffffff 00000005 00000000 00000001 00000000 807d0000 00000009 808ac820 00000001 808338d0 00000001 803bf1b0 00000008 81390008 Call Trace: [<8000d018>] show_stack+0x30/0x100 [<8032e66c>] dump_stack+0xa4/0xd4 [<8002db1c>] __warn+0xc0/0x134 [<8002dbec>] warn_slowpath_fmt+0x5c/0xac [<80033b34>] devm_request_resource+0xfc/0x10c [<80365ff8>] devm_request_pci_bus_resources+0x58/0xdc [<8048e13c>] mt7621_pci_probe+0x8dc/0xe48 [<803d2140>] platform_drv_probe+0x40/0x94 [<803cfd94>] really_probe+0x108/0x4ec [<803cd958>] bus_for_each_drv+0x70/0xb0 [<803d0388>] __device_attach+0xec/0x164 [<803cec8c>] bus_probe_device+0xa4/0xc0 [<803cf1c4>] deferred_probe_work_func+0x80/0xc4 [<80048444>] process_one_work+0x260/0x510 [<80048a4c>] worker_thread+0x358/0x5cc [<8004f7d0>] kthread+0x134/0x13c [<80007478>] ret_from_kernel_thread+0x14/0x1c ---[ end trace a9dd2e37537510d3 ]--- mt7621-pci 1e140000.pcie: Error requesting resources mt7621-pci: probe of 1e140000.pcie failed with error -16 ... With commit 669cbc708122 ("PCI: Move DT resource setup into devm_pci_alloc_host_bridge()"), the DT 'ranges' is parsed and populated into resources when the host bridge is allocated. The resources are requested as well, but that happens a 2nd time for this driver in mt7621_pcie_request_resources(). Hence we should avoid this second request. Also, the bus ranges was also populated by default, so we can remove it from mt7621_pcie_request_resources() to avoid the following trace if we don't avoid it: pci_bus 0000:00: busn_res: can not insert [bus 00-ff] under domain [bus 00-ff] (conflicts with (null) [bus 00-ff]) Function 'mt7621_pcie_request_resources' has been renamed into 'mt7621_pcie_add_resources' which now is a more accurate name for this function. Cc: stable at vger.kernel.org#5.9.x- Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index f961b353c22e..8831db383fad 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -653,16 +653,11 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie) return 0; } -static int mt7621_pcie_request_resources(struct mt7621_pcie *pcie, - struct list_head *res) +static void mt7621_pcie_add_resources(struct mt7621_pcie *pcie, + struct list_head *res) { - struct device *dev = pcie->dev; - pci_add_resource_offset(res, &pcie->io, pcie->offset.io); pci_add_resource_offset(res, &pcie->mem, pcie->offset.mem); - pci_add_resource(res, &pcie->busn); - - return devm_request_pci_bus_resources(dev, res); } static int mt7621_pcie_register_host(struct pci_host_bridge *host, @@ -738,11 +733,7 @@ static int mt7621_pci_probe(struct platform_device *pdev) setup_cm_memory_region(pcie); - err = mt7621_pcie_request_resources(pcie, &res); - if (err) { - dev_err(dev, "Error requesting resources\n"); - return err; - } + mt7621_pcie_add_resources(pcie, &res); err = mt7621_pcie_register_host(bridge, &res); if (err) { -- 2.25.1 From lkp at intel.com Mon Nov 2 21:05:31 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 03 Nov 2020 05:05:31 +0800 Subject: [staging:staging-next] BUILD SUCCESS 83e63b2cc416904b50895eeee8d8e0d7ea0418fe Message-ID: <5fa0749b.gBj4zZiybrYFdj+F%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-next branch HEAD: 83e63b2cc416904b50895eeee8d8e0d7ea0418fe Merge 5.10-rc2 into staging-next elapsed time: 721m configs tested: 188 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig c6x evmc6457_defconfig arm imx_v6_v7_defconfig powerpc cm5200_defconfig arm magician_defconfig powerpc skiroot_defconfig sh sh7757lcr_defconfig arm vt8500_v6_v7_defconfig powerpc amigaone_defconfig arm spear6xx_defconfig arm mmp2_defconfig ia64 generic_defconfig mips maltaup_xpa_defconfig sh rsk7269_defconfig arm tct_hammer_defconfig arm xcep_defconfig sh rts7751r2dplus_defconfig mips maltasmvp_defconfig nios2 10m50_defconfig sh se7712_defconfig mips mpc30x_defconfig powerpc currituck_defconfig m68k alldefconfig sh se7724_defconfig arm lart_defconfig powerpc mpc5200_defconfig sh urquell_defconfig powerpc ep88xc_defconfig powerpc canyonlands_defconfig arm simpad_defconfig arm footbridge_defconfig arm lpc32xx_defconfig sh se7343_defconfig riscv allmodconfig mips maltaaprp_defconfig arc axs101_defconfig arc vdk_hs38_defconfig mips allyesconfig arm omap1_defconfig m68k mvme16x_defconfig mips bcm47xx_defconfig mips gpr_defconfig powerpc mpc837x_mds_defconfig powerpc maple_defconfig riscv nommu_k210_defconfig powerpc mpc832x_rdb_defconfig c6x defconfig arm oxnas_v6_defconfig m68k m5208evb_defconfig powerpc obs600_defconfig powerpc asp8347_defconfig mips tb0226_defconfig mips ath25_defconfig i386 allyesconfig powerpc pasemi_defconfig parisc defconfig m68k m5407c3_defconfig powerpc taishan_defconfig nds32 alldefconfig powerpc redwood_defconfig arm shmobile_defconfig arm cns3420vb_defconfig mips ath79_defconfig arc hsdk_defconfig m68k sun3x_defconfig powerpc tqm8548_defconfig um kunit_defconfig arc haps_hs_smp_defconfig m68k bvme6000_defconfig arm vf610m4_defconfig arm mv78xx0_defconfig powerpc ppc40x_defconfig sh se7750_defconfig sh sdk7780_defconfig powerpc eiger_defconfig m68k multi_defconfig arm socfpga_defconfig riscv allyesconfig arm badge4_defconfig arm sunxi_defconfig sh ecovec24_defconfig riscv rv32_defconfig mips workpad_defconfig x86_64 allyesconfig powerpc holly_defconfig arm qcom_defconfig sh se7619_defconfig mips malta_kvm_guest_defconfig mips jmr3927_defconfig powerpc mpc836x_rdk_defconfig mips malta_qemu_32r6_defconfig i386 defconfig powerpc cell_defconfig sh microdev_defconfig powerpc rainier_defconfig powerpc katmai_defconfig powerpc ge_imp3a_defconfig powerpc mpc8313_rdb_defconfig powerpc gamecube_defconfig powerpc tqm8541_defconfig sh ecovec24-romimage_defconfig sh sh7770_generic_defconfig arm multi_v5_defconfig h8300 edosk2674_defconfig sh sh2007_defconfig ia64 alldefconfig mips cobalt_defconfig microblaze nommu_defconfig arm gemini_defconfig sparc sparc32_defconfig powerpc allnoconfig powerpc tqm8xx_defconfig powerpc chrp32_defconfig sh edosk7760_defconfig riscv alldefconfig m68k mvme147_defconfig mips ip27_defconfig xtensa smp_lx200_defconfig m68k sun3_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig s390 allyesconfig parisc allyesconfig s390 defconfig sparc allyesconfig sparc defconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig i386 randconfig-a004-20201102 i386 randconfig-a006-20201102 i386 randconfig-a005-20201102 i386 randconfig-a001-20201102 i386 randconfig-a002-20201102 i386 randconfig-a003-20201102 i386 randconfig-a004-20201101 i386 randconfig-a006-20201101 i386 randconfig-a005-20201101 i386 randconfig-a001-20201101 i386 randconfig-a002-20201101 i386 randconfig-a003-20201101 x86_64 randconfig-a012-20201102 x86_64 randconfig-a015-20201102 x86_64 randconfig-a011-20201102 x86_64 randconfig-a013-20201102 x86_64 randconfig-a014-20201102 x86_64 randconfig-a016-20201102 i386 randconfig-a013-20201102 i386 randconfig-a015-20201102 i386 randconfig-a014-20201102 i386 randconfig-a016-20201102 i386 randconfig-a011-20201102 i386 randconfig-a012-20201102 riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig x86_64 rhel x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a004-20201102 x86_64 randconfig-a005-20201102 x86_64 randconfig-a003-20201102 x86_64 randconfig-a002-20201102 x86_64 randconfig-a006-20201102 x86_64 randconfig-a001-20201102 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From Christian.Gromm at microchip.com Mon Nov 2 23:17:40 2020 From: Christian.Gromm at microchip.com (Christian.Gromm at microchip.com) Date: Mon, 2 Nov 2020 23:17:40 +0000 Subject: [PATCH] drivers: most: add ALSA sound driver In-Reply-To: <20201102153145.GA1034326@kroah.com> References: <1604330043-5517-1-git-send-email-christian.gromm@microchip.com> <20201102153145.GA1034326@kroah.com> Message-ID: On Mon, 2020-11-02 at 16:31 +0100, Greg KH wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you > know the content is safe > > On Mon, Nov 02, 2020 at 04:14:03PM +0100, Christian Gromm wrote: > > This patch moves the ALSA sound driver out of the staging area and > > adds it > > to the stable part of the MOST driver. Modifications to the > > Makefiles and > > Kconfigs are done accordingly to not break the build. > > > > Signed-off-by: Christian Gromm > > --- > > drivers/most/Kconfig | 10 + > > drivers/most/Makefile | 1 + > > drivers/most/most_snd.c | 753 > > ++++++++++++++++++++++++++++++++++++ > > drivers/staging/most/Kconfig | 2 - > > drivers/staging/most/Makefile | 1 - > > drivers/staging/most/sound/Kconfig | 14 - > > drivers/staging/most/sound/Makefile | 4 - > > drivers/staging/most/sound/sound.c | 753 ------------------------ > > ------------ > > 8 files changed, 764 insertions(+), 774 deletions(-) > > create mode 100644 drivers/most/most_snd.c > > delete mode 100644 drivers/staging/most/sound/Kconfig > > delete mode 100644 drivers/staging/most/sound/Makefile > > delete mode 100644 drivers/staging/most/sound/sound.c > > > > diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig > > index ebfe84e..4b8145b 100644 > > --- a/drivers/most/Kconfig > > +++ b/drivers/most/Kconfig > > @@ -32,4 +32,14 @@ config MOST_CDEV > > > > To compile this driver as a module, choose M here: the > > module will be called most_cdev. > > + > > +config MOST_SND > > + tristate "Sound" > > + depends on SND > > + select SND_PCM > > + help > > + Say Y here if you want to commumicate via ALSA/sound > > devices. > > + > > + To compile this driver as a module, choose M here: the > > + module will be called most_sound. > > endif > > diff --git a/drivers/most/Makefile b/drivers/most/Makefile > > index 8b53ca4..60db6cd 100644 > > --- a/drivers/most/Makefile > > +++ b/drivers/most/Makefile > > @@ -5,3 +5,4 @@ most_core-y := core.o \ > > > > obj-$(CONFIG_MOST_USB_HDM) += most_usb.o > > obj-$(CONFIG_MOST_CDEV) += most_cdev.o > > +obj-$(CONFIG_MOST_SND) += most_snd.o > > diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c > > new file mode 100644 > > index 0000000..8a449ab > > --- /dev/null > > +++ b/drivers/most/most_snd.c > > @@ -0,0 +1,753 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * sound.c - Sound component for Mostcore > > + * > > + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. > > KG > > + */ > > + > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define DRIVER_NAME "sound" > > +#define STRING_SIZE 80 > > + > > +static struct most_component comp; > > + > > +/** > > + * struct channel - private structure to keep channel specific > > data > > + * @substream: stores the substream structure > > + * @iface: interface for which the channel belongs to > > + * @cfg: channel configuration > > + * @card: registered sound card > > + * @list: list for private use > > + * @id: channel index > > + * @period_pos: current period position (ring buffer) > > + * @buffer_pos: current buffer position (ring buffer) > > + * @is_stream_running: identifies whether a stream is running or > > not > > + * @opened: set when the stream is opened > > + * @playback_task: playback thread > > + * @playback_waitq: waitq used by playback thread > > + */ > > +struct channel { > > + struct snd_pcm_substream *substream; > > + struct snd_pcm_hardware pcm_hardware; > > + struct most_interface *iface; > > + struct most_channel_config *cfg; > > + struct snd_card *card; > > + struct list_head list; > > + int id; > > + unsigned int period_pos; > > + unsigned int buffer_pos; > > + bool is_stream_running; > > + struct task_struct *playback_task; > > + wait_queue_head_t playback_waitq; > > + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); > > +}; > > + > > +struct sound_adapter { > > + struct list_head dev_list; > > + struct most_interface *iface; > > + struct snd_card *card; > > + struct list_head list; > > + bool registered; > > + int pcm_dev_idx; > > +}; > > + > > +static struct list_head adpt_list; > > + > > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > > + SNDRV_PCM_INFO_MMAP_VALID | \ > > + SNDRV_PCM_INFO_BATCH | \ > > + SNDRV_PCM_INFO_INTERLEAVED | \ > > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > > + > > +#define swap16(val) ( \ > > + (((u16)(val) << 8) & (u16)0xFF00) | \ > > + (((u16)(val) >> 8) & (u16)0x00FF)) > > + > > +#define swap32(val) ( \ > > + (((u32)(val) << 24) & (u32)0xFF000000) | \ > > + (((u32)(val) << 8) & (u32)0x00FF0000) | \ > > + (((u32)(val) >> 8) & (u32)0x0000FF00) | \ > > + (((u32)(val) >> 24) & (u32)0x000000FF)) > > Doesn't swab16() and swab32() work for this? I don't think you need > to > reimplement these. > > > + > > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int > > bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < (bytes / 2)) { > > + dest[i] = swap16(source[i]); > > + i++; > > + } > > +} > > + > > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int > > bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < bytes - 2) { > > + dest[i] = source[i + 2]; > > + dest[i + 1] = source[i + 1]; > > + dest[i + 2] = source[i]; > > + i += 3; > > + } > > +} > > + > > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int > > bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < bytes / 4) { > > + dest[i] = swap32(source[i]); > > + i++; > > + } > > +} > > Same for the above, don't we have functions for this? Can't find any of those. Do you happen to have a pointer where those functions are? thanks, Chris From lkp at intel.com Tue Nov 3 00:51:04 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 03 Nov 2020 08:51:04 +0800 Subject: [driver-core:driver-core-linus] BUILD SUCCESS 9d4fdda3344611ec53ededccc0c13cb149ba4375 Message-ID: <5fa0a978.KyOwE75umRS1e4Ok%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git driver-core-linus branch HEAD: 9d4fdda3344611ec53ededccc0c13cb149ba4375 scripts: get_api.pl: Add sub-titles to ABI output elapsed time: 723m configs tested: 176 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 defconfig arm allyesconfig arm64 allyesconfig arm allmodconfig c6x evmc6457_defconfig arm imx_v6_v7_defconfig powerpc cm5200_defconfig arm magician_defconfig powerpc skiroot_defconfig sh sh7757lcr_defconfig arm vt8500_v6_v7_defconfig powerpc amigaone_defconfig arm spear6xx_defconfig arm mmp2_defconfig ia64 generic_defconfig mips maltaup_xpa_defconfig sh rsk7269_defconfig arm tct_hammer_defconfig arm xcep_defconfig sh rts7751r2dplus_defconfig mips maltasmvp_defconfig m68k alldefconfig sh se7724_defconfig arm lart_defconfig sh se7750_defconfig arm at91_dt_defconfig arm zx_defconfig sh se7343_defconfig sh hp6xx_defconfig powerpc makalu_defconfig sh polaris_defconfig m68k bvme6000_defconfig arm lpc32xx_defconfig ia64 zx1_defconfig powerpc maple_defconfig mips ip28_defconfig arm lpc18xx_defconfig c6x dsk6455_defconfig powerpc kilauea_defconfig arc axs101_defconfig arc vdk_hs38_defconfig arm omap1_defconfig mips allyesconfig mips fuloong2e_defconfig arm mvebu_v5_defconfig powerpc ppc6xx_defconfig m68k mvme16x_defconfig mips bcm47xx_defconfig mips gpr_defconfig alpha defconfig powerpc mpc837x_mds_defconfig ia64 allyesconfig m68k m5208evb_defconfig powerpc obs600_defconfig powerpc asp8347_defconfig mips tb0226_defconfig mips ath25_defconfig powerpc mpc5200_defconfig arm cerfcube_defconfig h8300 h8300h-sim_defconfig m68k stmark2_defconfig sh rsk7201_defconfig mips sb1250_swarm_defconfig arm davinci_all_defconfig mips decstation_defconfig powerpc mpc8315_rdb_defconfig arc haps_hs_smp_defconfig arm vf610m4_defconfig arm mv78xx0_defconfig powerpc ppc40x_defconfig sh sdk7780_defconfig powerpc eiger_defconfig m68k multi_defconfig arm socfpga_defconfig riscv allyesconfig arm badge4_defconfig arm sunxi_defconfig mips maltaaprp_defconfig xtensa generic_kc705_defconfig sh sh7770_generic_defconfig csky defconfig powerpc mpc832x_rdb_defconfig m68k amiga_defconfig arc nsim_700_defconfig mips malta_kvm_guest_defconfig mips jmr3927_defconfig powerpc currituck_defconfig sh microdev_defconfig powerpc rainier_defconfig arm footbridge_defconfig powerpc katmai_defconfig powerpc ge_imp3a_defconfig powerpc mpc8313_rdb_defconfig powerpc gamecube_defconfig powerpc allmodconfig sh se7206_defconfig microblaze mmu_defconfig powerpc tqm8541_defconfig sh ecovec24-romimage_defconfig arm multi_v5_defconfig powerpc tqm5200_defconfig powerpc lite5200b_defconfig m68k mvme147_defconfig c6x defconfig sh sh7710voipgw_defconfig mips ip27_defconfig xtensa smp_lx200_defconfig m68k sun3_defconfig powerpc cell_defconfig arm pxa3xx_defconfig arm cns3420vb_defconfig arm colibri_pxa270_defconfig m68k allyesconfig ia64 allmodconfig ia64 defconfig m68k allmodconfig m68k defconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allmodconfig powerpc allyesconfig powerpc allnoconfig i386 randconfig-a004-20201102 i386 randconfig-a006-20201102 i386 randconfig-a005-20201102 i386 randconfig-a001-20201102 i386 randconfig-a002-20201102 i386 randconfig-a003-20201102 x86_64 randconfig-a012-20201102 x86_64 randconfig-a015-20201102 x86_64 randconfig-a011-20201102 x86_64 randconfig-a013-20201102 x86_64 randconfig-a014-20201102 x86_64 randconfig-a016-20201102 i386 randconfig-a013-20201102 i386 randconfig-a015-20201102 i386 randconfig-a014-20201102 i386 randconfig-a016-20201102 i386 randconfig-a011-20201102 i386 randconfig-a012-20201102 riscv nommu_k210_defconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a004-20201102 x86_64 randconfig-a005-20201102 x86_64 randconfig-a003-20201102 x86_64 randconfig-a002-20201102 x86_64 randconfig-a006-20201102 x86_64 randconfig-a001-20201102 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From lkp at intel.com Tue Nov 3 01:03:09 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 03 Nov 2020 09:03:09 +0800 Subject: [staging:staging-testing] BUILD SUCCESS 9364a2cf567187c0a075942c22d1f434c758de5d Message-ID: <5fa0ac4d.J0TOVm7yndIK74Zb%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: 9364a2cf567187c0a075942c22d1f434c758de5d staging: wimax: depends on NET elapsed time: 720m configs tested: 166 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 defconfig arm allyesconfig arm64 allyesconfig arm allmodconfig c6x evmc6457_defconfig arm imx_v6_v7_defconfig powerpc cm5200_defconfig arm magician_defconfig powerpc skiroot_defconfig sh sh7757lcr_defconfig arm vt8500_v6_v7_defconfig powerpc amigaone_defconfig arm spear6xx_defconfig arm mmp2_defconfig ia64 generic_defconfig mips maltaup_xpa_defconfig sh rsk7269_defconfig arm tct_hammer_defconfig arm xcep_defconfig sh rts7751r2dplus_defconfig mips maltasmvp_defconfig sh se7750_defconfig arm at91_dt_defconfig arm zx_defconfig sh se7343_defconfig sh hp6xx_defconfig powerpc makalu_defconfig sh polaris_defconfig sh se7724_defconfig m68k bvme6000_defconfig arm lpc32xx_defconfig ia64 zx1_defconfig powerpc maple_defconfig mips ip28_defconfig arm lpc18xx_defconfig c6x dsk6455_defconfig powerpc kilauea_defconfig arc axs101_defconfig arc vdk_hs38_defconfig arm omap1_defconfig mips allyesconfig mips fuloong2e_defconfig arm mvebu_v5_defconfig powerpc ppc6xx_defconfig m68k mvme16x_defconfig mips bcm47xx_defconfig mips gpr_defconfig alpha defconfig powerpc mpc837x_mds_defconfig ia64 allyesconfig powerpc mpc5200_defconfig arm cerfcube_defconfig h8300 h8300h-sim_defconfig m68k stmark2_defconfig sh rsk7201_defconfig mips sb1250_swarm_defconfig arm davinci_all_defconfig mips decstation_defconfig powerpc mpc8315_rdb_defconfig powerpc klondike_defconfig arm pcm027_defconfig sh secureedge5410_defconfig microblaze mmu_defconfig arm trizeps4_defconfig arc haps_hs_smp_defconfig arm vf610m4_defconfig arm mv78xx0_defconfig powerpc ppc40x_defconfig sh sdk7780_defconfig powerpc eiger_defconfig m68k multi_defconfig arm socfpga_defconfig arm badge4_defconfig arm sunxi_defconfig mips maltaaprp_defconfig xtensa generic_kc705_defconfig powerpc obs600_defconfig sh sh7770_generic_defconfig csky defconfig nds32 alldefconfig riscv nommu_k210_defconfig sh ecovec24_defconfig riscv rv32_defconfig mips malta_kvm_guest_defconfig mips jmr3927_defconfig powerpc currituck_defconfig powerpc ge_imp3a_defconfig powerpc mpc8313_rdb_defconfig powerpc gamecube_defconfig powerpc allmodconfig sh se7206_defconfig m68k m5208evb_defconfig powerpc tqm8541_defconfig sh ecovec24-romimage_defconfig arm multi_v5_defconfig powerpc tqm5200_defconfig powerpc lite5200b_defconfig m68k mvme147_defconfig c6x defconfig sh sh7710voipgw_defconfig arm pxa3xx_defconfig arm cns3420vb_defconfig arm colibri_pxa270_defconfig m68k allyesconfig ia64 allmodconfig ia64 defconfig m68k allmodconfig m68k defconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allmodconfig powerpc allyesconfig powerpc allnoconfig i386 randconfig-a004-20201102 i386 randconfig-a006-20201102 i386 randconfig-a005-20201102 i386 randconfig-a001-20201102 i386 randconfig-a002-20201102 i386 randconfig-a003-20201102 x86_64 randconfig-a012-20201102 x86_64 randconfig-a015-20201102 x86_64 randconfig-a011-20201102 x86_64 randconfig-a013-20201102 x86_64 randconfig-a014-20201102 x86_64 randconfig-a016-20201102 i386 randconfig-a013-20201102 i386 randconfig-a014-20201102 i386 randconfig-a016-20201102 i386 randconfig-a011-20201102 i386 randconfig-a012-20201102 i386 randconfig-a015-20201102 riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a004-20201102 x86_64 randconfig-a005-20201102 x86_64 randconfig-a003-20201102 x86_64 randconfig-a002-20201102 x86_64 randconfig-a006-20201102 x86_64 randconfig-a001-20201102 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From sashal at kernel.org Tue Nov 3 01:18:34 2020 From: sashal at kernel.org (Sasha Levin) Date: Mon, 2 Nov 2020 20:18:34 -0500 Subject: [PATCH AUTOSEL 5.9 29/35] staging: mmal-vchiq: Fix memory leak for vchiq_instance In-Reply-To: <20201103011840.182814-1-sashal@kernel.org> References: <20201103011840.182814-1-sashal@kernel.org> Message-ID: <20201103011840.182814-29-sashal@kernel.org> From: Seung-Woo Kim [ Upstream commit b6ae84d648954fae096d94faea1ddb6518b27841 ] The vchiq_instance is allocated with vchiq_initialise() but never freed properly. Fix memory leak for the vchiq_instance. Reported-by: Jaehoon Chung Signed-off-by: Seung-Woo Kim Link: https://lore.kernel.org/r/1603706150-10806-1-git-send-email-sw0312.kim at samsung.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- .../vc04_services/vchiq-mmal/mmal-vchiq.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c index e798d494f00ff..bbf033ca47362 100644 --- a/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c +++ b/drivers/staging/vc04_services/vchiq-mmal/mmal-vchiq.c @@ -179,6 +179,9 @@ struct vchiq_mmal_instance { /* ordered workqueue to process all bulk operations */ struct workqueue_struct *bulk_wq; + + /* handle for a vchiq instance */ + struct vchiq_instance *vchiq_instance; }; static struct mmal_msg_context * @@ -1840,6 +1843,7 @@ int vchiq_mmal_finalise(struct vchiq_mmal_instance *instance) mutex_unlock(&instance->vchiq_mutex); + vchiq_shutdown(instance->vchiq_instance); flush_workqueue(instance->bulk_wq); destroy_workqueue(instance->bulk_wq); @@ -1856,6 +1860,7 @@ EXPORT_SYMBOL_GPL(vchiq_mmal_finalise); int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) { int status; + int err = -ENODEV; struct vchiq_mmal_instance *instance; static struct vchiq_instance *vchiq_instance; struct vchiq_service_params params = { @@ -1890,17 +1895,21 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) status = vchiq_connect(vchiq_instance); if (status) { pr_err("Failed to connect VCHI instance (status=%d)\n", status); - return -EIO; + err = -EIO; + goto err_shutdown_vchiq; } instance = kzalloc(sizeof(*instance), GFP_KERNEL); - if (!instance) - return -ENOMEM; + if (!instance) { + err = -ENOMEM; + goto err_shutdown_vchiq; + } mutex_init(&instance->vchiq_mutex); instance->bulk_scratch = vmalloc(PAGE_SIZE); + instance->vchiq_instance = vchiq_instance; mutex_init(&instance->context_map_lock); idr_init_base(&instance->context_map, 1); @@ -1932,7 +1941,9 @@ int vchiq_mmal_init(struct vchiq_mmal_instance **out_instance) err_free: vfree(instance->bulk_scratch); kfree(instance); - return -ENODEV; +err_shutdown_vchiq: + vchiq_shutdown(vchiq_instance); + return err; } EXPORT_SYMBOL_GPL(vchiq_mmal_init); -- 2.27.0 From siddhantgupta416 at gmail.com Tue Nov 3 04:40:39 2020 From: siddhantgupta416 at gmail.com (siddhant gupta) Date: Tue, 3 Nov 2020 10:10:39 +0530 Subject: [PATCH] staging: mt7621-dma: Prefer Using BIT Macro instead of left shifting on 1. In-Reply-To: <20201102194055.GA2429929@kroah.com> References: <20201102193402.GA14965@Sleakybeast> <20201102194055.GA2429929@kroah.com> Message-ID: On Tue, 3 Nov 2020 at 01:10, Greg KH wrote: > > On Tue, Nov 03, 2020 at 01:04:02AM +0530, siddhant gupta(siddhant1223) wrote: > > > > Replace left shifting on 1 by a BIT macro to fix checkpatch warning. > > > > Signed-off-by: Siddhant Gupta > > > > --- > > drivers/staging/mt7621-dma/mtk-hsdma.c | 2 +- > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c > > index 354536783e1c..a9e1a1b14035 100644 > > --- a/drivers/staging/mt7621-dma/mtk-hsdma.c > > +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c > > @@ -72,7 +72,7 @@ > > #define HSDMA_GLO_TX_DMA BIT(0) > > > > #define HSDMA_BT_SIZE_16BYTES (0 << HSDMA_GLO_BT_SHIFT) > > -#define HSDMA_BT_SIZE_32BYTES (1 << HSDMA_GLO_BT_SHIFT) > > +#define HSDMA_BT_SIZE_32BYTES BIT(HSDMA_GLO_BT_SHIFT) > > #define HSDMA_BT_SIZE_64BYTES (2 << HSDMA_GLO_BT_SHIFT) > > #define HSDMA_BT_SIZE_128BYTES (3 << HSDMA_GLO_BT_SHIFT) > > In looking at the code, does this change really make sense? > > (hint, I don't think so...) Following Checkpatch, I thought it might be good to do as checkpatch said, but the code looks better and more readable without the change. This is my first patch and also a lesson that i should not fix every checkpatch warnings. I'll pick something better next time Thanks for your comment . From gregkh at linuxfoundation.org Tue Nov 3 06:39:36 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Tue, 3 Nov 2020 07:39:36 +0100 Subject: [PATCH] drivers: most: add ALSA sound driver In-Reply-To: References: <1604330043-5517-1-git-send-email-christian.gromm@microchip.com> <20201102153145.GA1034326@kroah.com> Message-ID: <20201103063936.GB74830@kroah.com> On Mon, Nov 02, 2020 at 11:17:40PM +0000, Christian.Gromm at microchip.com wrote: > On Mon, 2020-11-02 at 16:31 +0100, Greg KH wrote: > > EXTERNAL EMAIL: Do not click links or open attachments unless you > > know the content is safe > > > > On Mon, Nov 02, 2020 at 04:14:03PM +0100, Christian Gromm wrote: > > > This patch moves the ALSA sound driver out of the staging area and > > > adds it > > > to the stable part of the MOST driver. Modifications to the > > > Makefiles and > > > Kconfigs are done accordingly to not break the build. > > > > > > Signed-off-by: Christian Gromm > > > --- > > > drivers/most/Kconfig | 10 + > > > drivers/most/Makefile | 1 + > > > drivers/most/most_snd.c | 753 > > > ++++++++++++++++++++++++++++++++++++ > > > drivers/staging/most/Kconfig | 2 - > > > drivers/staging/most/Makefile | 1 - > > > drivers/staging/most/sound/Kconfig | 14 - > > > drivers/staging/most/sound/Makefile | 4 - > > > drivers/staging/most/sound/sound.c | 753 ------------------------ > > > ------------ > > > 8 files changed, 764 insertions(+), 774 deletions(-) > > > create mode 100644 drivers/most/most_snd.c > > > delete mode 100644 drivers/staging/most/sound/Kconfig > > > delete mode 100644 drivers/staging/most/sound/Makefile > > > delete mode 100644 drivers/staging/most/sound/sound.c > > > > > > diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig > > > index ebfe84e..4b8145b 100644 > > > --- a/drivers/most/Kconfig > > > +++ b/drivers/most/Kconfig > > > @@ -32,4 +32,14 @@ config MOST_CDEV > > > > > > To compile this driver as a module, choose M here: the > > > module will be called most_cdev. > > > + > > > +config MOST_SND > > > + tristate "Sound" > > > + depends on SND > > > + select SND_PCM > > > + help > > > + Say Y here if you want to commumicate via ALSA/sound > > > devices. > > > + > > > + To compile this driver as a module, choose M here: the > > > + module will be called most_sound. > > > endif > > > diff --git a/drivers/most/Makefile b/drivers/most/Makefile > > > index 8b53ca4..60db6cd 100644 > > > --- a/drivers/most/Makefile > > > +++ b/drivers/most/Makefile > > > @@ -5,3 +5,4 @@ most_core-y := core.o \ > > > > > > obj-$(CONFIG_MOST_USB_HDM) += most_usb.o > > > obj-$(CONFIG_MOST_CDEV) += most_cdev.o > > > +obj-$(CONFIG_MOST_SND) += most_snd.o > > > diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c > > > new file mode 100644 > > > index 0000000..8a449ab > > > --- /dev/null > > > +++ b/drivers/most/most_snd.c > > > @@ -0,0 +1,753 @@ > > > +// SPDX-License-Identifier: GPL-2.0 > > > +/* > > > + * sound.c - Sound component for Mostcore > > > + * > > > + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. > > > KG > > > + */ > > > + > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > > + > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > +#include > > > + > > > +#define DRIVER_NAME "sound" > > > +#define STRING_SIZE 80 > > > + > > > +static struct most_component comp; > > > + > > > +/** > > > + * struct channel - private structure to keep channel specific > > > data > > > + * @substream: stores the substream structure > > > + * @iface: interface for which the channel belongs to > > > + * @cfg: channel configuration > > > + * @card: registered sound card > > > + * @list: list for private use > > > + * @id: channel index > > > + * @period_pos: current period position (ring buffer) > > > + * @buffer_pos: current buffer position (ring buffer) > > > + * @is_stream_running: identifies whether a stream is running or > > > not > > > + * @opened: set when the stream is opened > > > + * @playback_task: playback thread > > > + * @playback_waitq: waitq used by playback thread > > > + */ > > > +struct channel { > > > + struct snd_pcm_substream *substream; > > > + struct snd_pcm_hardware pcm_hardware; > > > + struct most_interface *iface; > > > + struct most_channel_config *cfg; > > > + struct snd_card *card; > > > + struct list_head list; > > > + int id; > > > + unsigned int period_pos; > > > + unsigned int buffer_pos; > > > + bool is_stream_running; > > > + struct task_struct *playback_task; > > > + wait_queue_head_t playback_waitq; > > > + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); > > > +}; > > > + > > > +struct sound_adapter { > > > + struct list_head dev_list; > > > + struct most_interface *iface; > > > + struct snd_card *card; > > > + struct list_head list; > > > + bool registered; > > > + int pcm_dev_idx; > > > +}; > > > + > > > +static struct list_head adpt_list; > > > + > > > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > > > + SNDRV_PCM_INFO_MMAP_VALID | \ > > > + SNDRV_PCM_INFO_BATCH | \ > > > + SNDRV_PCM_INFO_INTERLEAVED | \ > > > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > > > + > > > +#define swap16(val) ( \ > > > + (((u16)(val) << 8) & (u16)0xFF00) | \ > > > + (((u16)(val) >> 8) & (u16)0x00FF)) > > > + > > > +#define swap32(val) ( \ > > > + (((u32)(val) << 24) & (u32)0xFF000000) | \ > > > + (((u32)(val) << 8) & (u32)0x00FF0000) | \ > > > + (((u32)(val) >> 8) & (u32)0x0000FF00) | \ > > > + (((u32)(val) >> 24) & (u32)0x000000FF)) > > > > Doesn't swab16() and swab32() work for this? I don't think you need > > to > > reimplement these. > > > > > + > > > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int > > > bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < (bytes / 2)) { > > > + dest[i] = swap16(source[i]); > > > + i++; > > > + } > > > +} > > > + > > > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int > > > bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < bytes - 2) { > > > + dest[i] = source[i + 2]; > > > + dest[i + 1] = source[i + 1]; > > > + dest[i + 2] = source[i]; > > > + i += 3; > > > + } > > > +} > > > + > > > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int > > > bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < bytes / 4) { > > > + dest[i] = swap32(source[i]); > > > + i++; > > > + } > > > +} > > > > Same for the above, don't we have functions for this? > > Can't find any of those. Do you happen to have a pointer where > those functions are? I assumed we might, given we have the other functions above. See where they are used? From hch at lst.de Tue Nov 3 09:55:38 2020 From: hch at lst.de (Christoph Hellwig) Date: Tue, 3 Nov 2020 10:55:38 +0100 Subject: use of dma_direct_set_offset in (allwinner) drivers Message-ID: <20201103095538.GA19136@lst.de> Hi all, Linux 5.10-rc1 switched from having a single dma offset in struct device to a set of DMA ranges, and introduced a new helper to set them, dma_direct_set_offset. This in fact surfaced that a bunch of drivers that violate our layering and set the offset from drivers, which meant we had to reluctantly export the symbol to set up the DMA range. The drivers are: drivers/gpu/drm/sun4i/sun4i_backend.c This just use dma_direct_set_offset as a fallback. Is there any good reason to not just kill off the fallback? drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c Same as above. drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c This driver unconditionally sets the offset. Why can't we do this in the device tree? drivers/staging/media/sunxi/cedrus/cedrus_hw.c Same as above. From jrdr.linux at gmail.com Wed Nov 4 02:02:11 2020 From: jrdr.linux at gmail.com (Souptick Joarder) Date: Wed, 4 Nov 2020 07:32:11 +0530 Subject: [PATCH v2] media: atomisp: Fixed error handling path Message-ID: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> Inside alloc_user_pages() based on flag value either pin_user_pages() or get_user_pages_fast() will be called. However, these API might fail. But free_user_pages() called in error handling path doesn't bother about return value and will try to unpin bo->pgnr pages, which is incorrect. Fix this by passing the page_nr to free_user_pages(). If page_nr > 0 pages will be unpinned based on bo->mem_type. This will also take care of non error handling path. Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory allocation") Signed-off-by: Souptick Joarder Reviewed-by: Dan Carpenter Cc: John Hubbard Cc: Ira Weiny Cc: Dan Carpenter --- v2: Added review tag. drivers/staging/media/atomisp/pci/hmm/hmm_bo.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c index f13af23..0168f98 100644 --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c @@ -857,16 +857,17 @@ static void free_private_pages(struct hmm_buffer_object *bo, kfree(bo->page_obj); } -static void free_user_pages(struct hmm_buffer_object *bo) +static void free_user_pages(struct hmm_buffer_object *bo, + unsigned int page_nr) { int i; hmm_mem_stat.usr_size -= bo->pgnr; if (bo->mem_type == HMM_BO_MEM_TYPE_PFN) { - unpin_user_pages(bo->pages, bo->pgnr); + unpin_user_pages(bo->pages, page_nr); } else { - for (i = 0; i < bo->pgnr; i++) + for (i = 0; i < page_nr; i++) put_page(bo->pages[i]); } kfree(bo->pages); @@ -942,6 +943,8 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, dev_err(atomisp_dev, "get_user_pages err: bo->pgnr = %d, pgnr actually pinned = %d.\n", bo->pgnr, page_nr); + if (page_nr < 0) + page_nr = 0; goto out_of_mem; } @@ -954,7 +957,7 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, out_of_mem: - free_user_pages(bo); + free_user_pages(bo, page_nr); return -ENOMEM; } @@ -1037,7 +1040,7 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo) if (bo->type == HMM_BO_PRIVATE) free_private_pages(bo, &dynamic_pool, &reserved_pool); else if (bo->type == HMM_BO_USER) - free_user_pages(bo); + free_user_pages(bo, bo->pgnr); else dev_err(atomisp_dev, "invalid buffer type.\n"); mutex_unlock(&bo->mutex); -- 1.9.1 From shubhraj at xilinx.com Wed Nov 4 04:07:33 2020 From: shubhraj at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 04:07:33 +0000 Subject: [PATCH v6 2/8] clk: clock-wizard: Add the clockwizard to clk directory In-Reply-To: <160072330324.310579.14466423524100614935@swboyd.mtv.corp.google.com> References: <1598621996-31040-1-git-send-email-shubhrajyoti.datta@xilinx.com> <1598621996-31040-3-git-send-email-shubhrajyoti.datta@xilinx.com> <160072319955.310579.4256832010356165092@swboyd.mtv.corp.google.com> <160072330324.310579.14466423524100614935@swboyd.mtv.corp.google.com> Message-ID: Hi Stephen, Thanks for the review. > -----Original Message----- > From: Stephen Boyd > Sent: Tuesday, September 22, 2020 2:52 AM > To: Shubhrajyoti Datta ; linux-clk at vger.kernel.org > Cc: devicetree at vger.kernel.org; linux-kernel at vger.kernel.org; > devel at driverdev.osuosl.org; robh+dt at kernel.org; > gregkh at linuxfoundation.org; mturquette at baylibre.com; Shubhrajyoti > Datta > Subject: Re: [PATCH v6 2/8] clk: clock-wizard: Add the clockwizard to clk > directory > > Quoting Stephen Boyd (2020-09-21 14:19:59) > > Quoting Shubhrajyoti Datta (2020-08-28 06:39:50) > > > Add clocking wizard driver to clk. > > > > > > Signed-off-by: Shubhrajyoti Datta > > > --- > > > > Can this be combined with patch #6? > > Sorry, I meant patch #8. Did not get the comment. Do you want to split the makefile and the driver parts of the patch. Or the whole of the patch to be merged. Or do you want the staging patch merged with here? [PATCH v6 8/8] staging: clocking-wizard: Delete the driver from the staging From Markus.Elfring at web.de Wed Nov 4 07:15:58 2020 From: Markus.Elfring at web.de (Markus Elfring) Date: Wed, 4 Nov 2020 08:15:58 +0100 Subject: [PATCH v2] media: atomisp: Fix error handling path In-Reply-To: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> Message-ID: <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> > Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory > allocation") Please delete a line break for this tag. Regards, Markus From maxime at cerno.tech Wed Nov 4 08:14:11 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Wed, 4 Nov 2020 09:14:11 +0100 Subject: use of dma_direct_set_offset in (allwinner) drivers In-Reply-To: <20201103095538.GA19136@lst.de> References: <20201103095538.GA19136@lst.de> Message-ID: <20201104081411.bnt5kixgunaczbzj@gilmour.lan> Hi Christoph, On Tue, Nov 03, 2020 at 10:55:38AM +0100, Christoph Hellwig wrote: > Linux 5.10-rc1 switched from having a single dma offset in struct device > to a set of DMA ranges, and introduced a new helper to set them, > dma_direct_set_offset. > > This in fact surfaced that a bunch of drivers that violate our layering > and set the offset from drivers, which meant we had to reluctantly > export the symbol to set up the DMA range. > > The drivers are: > > drivers/gpu/drm/sun4i/sun4i_backend.c > > This just use dma_direct_set_offset as a fallback. Is there any good > reason to not just kill off the fallback? > > drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c > > Same as above. So, the history of this is: - We initially introduced the support for those two controllers assuming that there was a direct mapping between the physical and DMA addresses. It turns out it didn't and the DMA accesses were going through a secondary, dedicated, bus that didn't have the same mapping of the RAM than the CPU. 4690803b09c6 ("drm/sun4i: backend: Offset layer buffer address by DRAM starting address") - This dedicated bus is undocumented and barely used in the vendor kernel so this was overlooked, and it's fairly hard to get infos on it for all the SoCs we support. We added the DT support for it though on some SoCs we had enough infos to do so: c43a4469402f ("dt-bindings: interconnect: Add a dma interconnect name") 22f88e311399 ("ARM: dts: sun5i: Add the MBUS controller") This explains the check on the interconnect property - However, due to the stable DT rule, we still need to operate without regressions on older DTs that wouldn't have that property (and for SoCs we haven't figured out). Hence the fallback. > drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c > > This driver unconditionally sets the offset. Why can't we do this > in the device tree? > > drivers/staging/media/sunxi/cedrus/cedrus_hw.c > > Same as above. > We should make those two match the previous ones, but we'll have the same issue here eventually. Most likely they were never ran on an SoC for which we have the MBUS figured out. Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From dan.carpenter at oracle.com Wed Nov 4 08:31:21 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Wed, 4 Nov 2020 11:31:21 +0300 Subject: [PATCH v2] media: atomisp: Fix error handling path In-Reply-To: <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> Message-ID: <20201104083121.GG18329@kadam> On Wed, Nov 04, 2020 at 08:15:58AM +0100, Markus Elfring wrote: > > Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory > > allocation") > > Please delete a line break for this tag. Markus, the thing is that we all saw the line break and we just thought it didn't matter at all... regards, dan carpenter From robin.murphy at arm.com Wed Nov 4 10:15:49 2020 From: robin.murphy at arm.com (Robin Murphy) Date: Wed, 4 Nov 2020 10:15:49 +0000 Subject: use of dma_direct_set_offset in (allwinner) drivers In-Reply-To: <20201104081411.bnt5kixgunaczbzj@gilmour.lan> References: <20201103095538.GA19136@lst.de> <20201104081411.bnt5kixgunaczbzj@gilmour.lan> Message-ID: <9623c346-c86c-e3ce-332b-95492576a859@arm.com> On 2020-11-04 08:14, Maxime Ripard wrote: > Hi Christoph, > > On Tue, Nov 03, 2020 at 10:55:38AM +0100, Christoph Hellwig wrote: >> Linux 5.10-rc1 switched from having a single dma offset in struct device >> to a set of DMA ranges, and introduced a new helper to set them, >> dma_direct_set_offset. >> >> This in fact surfaced that a bunch of drivers that violate our layering >> and set the offset from drivers, which meant we had to reluctantly >> export the symbol to set up the DMA range. >> >> The drivers are: >> >> drivers/gpu/drm/sun4i/sun4i_backend.c >> >> This just use dma_direct_set_offset as a fallback. Is there any good >> reason to not just kill off the fallback? >> >> drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c >> >> Same as above. > > So, the history of this is: > > - We initially introduced the support for those two controllers > assuming that there was a direct mapping between the physical and > DMA addresses. It turns out it didn't and the DMA accesses were > going through a secondary, dedicated, bus that didn't have the same > mapping of the RAM than the CPU. > > 4690803b09c6 ("drm/sun4i: backend: Offset layer buffer address by DRAM starting address") > > - This dedicated bus is undocumented and barely used in the vendor > kernel so this was overlooked, and it's fairly hard to get infos on > it for all the SoCs we support. We added the DT support for it > though on some SoCs we had enough infos to do so: > > c43a4469402f ("dt-bindings: interconnect: Add a dma interconnect name") > 22f88e311399 ("ARM: dts: sun5i: Add the MBUS controller") > > This explains the check on the interconnect property > > - However, due to the stable DT rule, we still need to operate without > regressions on older DTs that wouldn't have that property (and for > SoCs we haven't figured out). Hence the fallback. How about having something in the platform code that keys off the top-level SoC compatible and uses a bus notifier to create offsets for the relevant devices if an MBUS description is missing? At least that way the workaround could be confined to a single dedicated place and look somewhat similar to other special cases like sta2x11, rather than being duplicated all over the place. Robin. >> drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c >> >> This driver unconditionally sets the offset. Why can't we do this >> in the device tree? >> >> drivers/staging/media/sunxi/cedrus/cedrus_hw.c >> >> Same as above. >> > > We should make those two match the previous ones, but we'll have the > same issue here eventually. Most likely they were never ran on an SoC > for which we have the MBUS figured out. > > Maxime > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > From hch at lst.de Wed Nov 4 10:29:23 2020 From: hch at lst.de (Christoph Hellwig) Date: Wed, 4 Nov 2020 11:29:23 +0100 Subject: use of dma_direct_set_offset in (allwinner) drivers In-Reply-To: <9623c346-c86c-e3ce-332b-95492576a859@arm.com> References: <20201103095538.GA19136@lst.de> <20201104081411.bnt5kixgunaczbzj@gilmour.lan> <9623c346-c86c-e3ce-332b-95492576a859@arm.com> Message-ID: <20201104102923.GA23981@lst.de> On Wed, Nov 04, 2020 at 10:15:49AM +0000, Robin Murphy wrote: > How about having something in the platform code that keys off the top-level > SoC compatible and uses a bus notifier to create offsets for the relevant > devices if an MBUS description is missing? At least that way the workaround > could be confined to a single dedicated place and look somewhat similar to > other special cases like sta2x11, rather than being duplicated all over the > place. Yes, that would be the right way to handle the issue. From paul.kocialkowski at bootlin.com Wed Nov 4 10:33:32 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:33:32 +0100 Subject: [PATCH 11/14] dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation In-Reply-To: <20201026165653.7tzo2hlagee633ra@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-12-paul.kocialkowski@bootlin.com> <20201026165653.7tzo2hlagee633ra@gilmour.lan> Message-ID: <20201104103332.GB285779@aptenodytes> Hi, On Mon 26 Oct 20, 17:56, Maxime Ripard wrote: > On Fri, Oct 23, 2020 at 07:45:43PM +0200, Paul Kocialkowski wrote: > > This introduces YAML bindings documentation for the A83T MIPI CSI-2 > > controller. > > > > Signed-off-by: Paul Kocialkowski > > What is the difference with the a31/v3s one? It's a different controller, not a variation of the A31 one. I'll rework the commit log to make this clearer. > > --- > > .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 ++++++++++++++++++ > > 1 file changed, 158 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > > > diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > new file mode 100644 > > index 000000000000..2384ae4e7be0 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > @@ -0,0 +1,158 @@ > > +# SPDX-License-Identifier: GPL-2.0 > > +%YAML 1.2 > > +--- > > +$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-mipi-csi2.yaml# > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > + > > +title: Allwinner A83T MIPI CSI-2 Device Tree Bindings > > + > > +maintainers: > > + - Paul Kocialkowski > > + > > +properties: > > + compatible: > > + const: allwinner,sun8i-a83t-mipi-csi2 > > + > > + reg: > > + maxItems: 1 > > + > > + interrupts: > > + maxItems: 1 > > + > > + clocks: > > + items: > > + - description: Bus Clock > > + - description: Module Clock > > + - description: MIPI-specific Clock > > + - description: Misc CSI Clock > > + > > + clock-names: > > + items: > > + - const: bus > > + - const: mod > > + - const: mipi > > + - const: misc > > If it's only due to the clock, it's soemething you can deal with in the > first schema, there's no need to duplicate them. It's a completely different controller so I don't think it makes sense to have a single schema for both. Even if the bindings look similar. Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From Markus.Elfring at web.de Wed Nov 4 10:30:29 2020 From: Markus.Elfring at web.de (Markus Elfring) Date: Wed, 4 Nov 2020 11:30:29 +0100 Subject: [v2] media: atomisp: Fix error handling path In-Reply-To: <20201104083121.GG18329@kadam> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> <20201104083121.GG18329@kadam> Message-ID: <85ff17ad-8aa7-a457-6e23-4f5c1c5152f2@web.de> >>> Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory >>> allocation") >> >> Please delete a line break for this tag. > > Markus, the thing is that we all saw the line break and we just thought > it didn't matter at all... Do you disagree to the known documentation then? https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?id=4ef8451b332662d004df269d4cdeb7d9f31419b5#n123 Regards, Markus From paul.kocialkowski at bootlin.com Wed Nov 4 10:37:31 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:37:31 +0100 Subject: [PATCH 12/14] media: sunxi: Add support for the A83T MIPI CSI-2 controller In-Reply-To: <20201026170041.qsjzxlurufuuhcsq@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-13-paul.kocialkowski@bootlin.com> <20201026170041.qsjzxlurufuuhcsq@gilmour.lan> Message-ID: <20201104103731.GC285779@aptenodytes> Hi, On Mon 26 Oct 20, 18:00, Maxime Ripard wrote: > On Fri, Oct 23, 2020 at 07:45:44PM +0200, Paul Kocialkowski wrote: > > The A83T supports MIPI CSI-2 with a composite controller, covering both the > > protocol logic and the D-PHY implementation. This controller seems to be found > > on the A83T only and probably was abandonned since. > > > > This implementation splits the protocol and D-PHY registers and uses the PHY > > framework internally. The D-PHY is not registered as a standalone PHY driver > > since it cannot be used with any other controller. > > > > There are a few notable points about the controller: > > - The initialisation sequence involes writing specific magic init values that > > do not seem to make any particular sense given the concerned register fields. > > - Interrupts appear to be hitting regardless of the interrupt mask registers, > > which can cause a serious flood when transmission errors occur. > > Ah, so it's a separate driver too. > > > This work is based on the first version of the driver submitted by > > K?vin L'h?pital, which was adapted to mainline from the Allwinner BSP. > > This version integrates MIPI CSI-2 support as a standalone V4L2 subdev > > instead of merging it in the sun6i-csi driver. > > > > It was tested on a Banana Pi M3 board with an OV8865 sensor in a 4-lane > > configuration. > > Co-developped-by and SoB from Kevin? Not really. I wrote this driver from scratch and even significantly reworked the register descriptions to the point that I don't think it makes sense to consider that he's an author. For parts that can be considered a derivative work, copyright attribution was given in the header. Cheers, Paul > Looking at the driver, the same comments from the v3s apply there > > Maxime -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From nsaenzjulienne at suse.de Wed Nov 4 10:39:26 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:26 +0100 Subject: [PATCH v3 00/11] Raspberry Pi PoE HAT fan support Message-ID: <20201104103938.1286-1-nsaenzjulienne@suse.de> The aim of this series is to add support to the fan found on RPi's PoE HAT. Some commentary on the design can be found below. But the imporant part to the people CC'd here not involved with PWM is that, in order to achieve this properly, we also have to fix the firmware interface the driver uses to communicate with the PWM bus (and many other low level functions). Specifically, we have to make sure the firmware interface isn't unbound while consumers are still up. So, patch #1 introduces reference counting in the firwmware interface driver and patches #2 to #7 update all firmware users. Patches #8 to #10 introduce the new PWM driver. I sent everything as a single series as the final version of the PWM drivers depends on the firwmare fixes, but I'll be happy to split this into two separate series if you think it's better. --- Original cover letter below --- This series aims at adding support to RPi's official PoE HAT fan[1]. The HW setup is the following: | Raspberry Pi | PoE HAT | arm core -> Mailbox -> RPi co-processor -> I2C -> Atmel MCU -> PWM -> FAN The arm cores have only access to the mailbox interface, as i2c0, even if physically accessible, is to be used solely by the co-processor (VideoCore 4/6). This series implements a PWM bus, and has pwm-fan sitting on top of it as per this discussion: https://lkml.org/lkml/2018/9/2/486. Although this design has a series of shortcomings: - It depends on a DT binding: it's not flexible if a new hat shows up with new functionality, we're not 100% sure we'll be able to expand it without breaking backwards compatibility. But without it we can't make use of DT thermal-zones, which IMO is overkill. - We're using pwm-fan, writing a hwmon driver would, again, give us more flexibility, but it's not really needed at the moment. I personally think that it's not worth the effort, it's unlikely we'll get things right in advance. And ultimately, if the RPi people come up with something new, we can always write a new driver/bindings from scratch (as in not reusing previous code). That said, I'm more than happy to change things if there is a consensus that another design will do the trick. [1] https://www.raspberrypi.org/blog/introducing-power-over-ethernet-poe-hat/ --- Changes since v2: - Introduce devm_rpi_firmware_get() - Small cleanups in PWM driver Changes since v1: - Address PWM driver changes - Fix binding, now with 2 cells - Add reference count to rpi_firmware_get() Nicolas Saenz Julienne (11): firmware: raspberrypi: Introduce devm_rpi_firmware_get() clk: bcm: rpi: Release firmware handle on unbind gpio: raspberrypi-exp: Release firmware handle on unbind reset: raspberrypi: Release firmware handle on unbind soc: bcm: raspberrypi-power: Release firmware handle on unbind staging: vchiq: Release firmware handle on unbind input: raspberrypi-ts: Release firmware handle when not needed firmware: raspberrypi: Get rid of rpi_firmware_get() dt-bindings: pwm: Add binding for RPi firmware PWM bus DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support pwm: Add Raspberry Pi Firmware based PWM bus .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 ++ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++ drivers/clk/bcm/clk-raspberrypi.c | 2 +- drivers/firmware/raspberrypi.c | 37 ++- drivers/gpio/gpio-raspberrypi-exp.c | 2 +- drivers/input/touchscreen/raspberrypi-ts.c | 2 +- drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++ drivers/reset/reset-raspberrypi.c | 2 +- drivers/soc/bcm/raspberrypi-power.c | 2 +- .../interface/vchiq_arm/vchiq_arm.c | 2 +- .../pwm/raspberrypi,firmware-pwm.h | 13 ++ include/soc/bcm2835/raspberrypi-firmware.h | 6 +- 14 files changed, 356 insertions(+), 12 deletions(-) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:27 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:27 +0100 Subject: [PATCH v3 01/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-2-nsaenzjulienne@suse.de> When unbinding the firmware device we need to make sure it has no consumers left. Otherwise we'd leave them with a firmware handle pointing at freed memory. Keep a reference count of all consumers and introduce devm_rpi_firmware_get() which will automatically decrease the reference count upon unbinding consumer drivers. Suggested-by: Uwe Kleine-K?nig Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Create devm_rpi_firmware_get() drivers/firmware/raspberrypi.c | 46 ++++++++++++++++++++++ include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++ 2 files changed, 54 insertions(+) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 2371d08bdd17..74bdb3bde9dc 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -11,7 +11,9 @@ #include #include #include +#include #include +#include #include #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) @@ -27,6 +29,9 @@ struct rpi_firmware { struct mbox_chan *chan; /* The property channel. */ struct completion c; u32 enabled; + + refcount_t consumers; + wait_queue_head_t wait; }; static DEFINE_MUTEX(transaction_lock); @@ -247,6 +252,8 @@ static int rpi_firmware_probe(struct platform_device *pdev) } init_completion(&fw->c); + refcount_set(&fw->consumers, 1); + init_waitqueue_head(&fw->wait); platform_set_drvdata(pdev, fw); @@ -275,11 +282,21 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_hwmon = NULL; platform_device_unregister(rpi_clk); rpi_clk = NULL; + + wait_event(fw->wait, refcount_dec_if_one(&fw->consumers)); mbox_free_channel(fw->chan); return 0; } +static void rpi_firmware_put(void *data) +{ + struct rpi_firmware *fw = data; + + refcount_dec(&fw->consumers); + wake_up(&fw->wait); +} + /** * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. @@ -297,6 +314,35 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) } EXPORT_SYMBOL_GPL(rpi_firmware_get); +/** + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. + * @firmware_node: Pointer to the firmware Device Tree node. + * + * Returns NULL is the firmware device is not ready. + */ +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + struct platform_device *pdev = of_find_device_by_node(firmware_node); + struct rpi_firmware *fw; + + if (!pdev) + return NULL; + + fw = platform_get_drvdata(pdev); + if (!fw) + return NULL; + + if (!refcount_inc_not_zero(&fw->consumers)) + return NULL; + + if (devm_add_action_or_reset(dev, rpi_firmware_put, fw)) + return NULL; + + return fw; +} +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); + static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index cc9cdbc66403..8fe64f53a394 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -141,6 +141,8 @@ int rpi_firmware_property(struct rpi_firmware *fw, int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -158,6 +160,12 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware { return NULL; } + +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + return NULL; +} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:28 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:28 +0100 Subject: [PATCH v3 02/11] clk: bcm: rpi: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-3-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/clk/bcm/clk-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f89b9cfc4309..dd3b71eafabf 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -314,7 +314,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) return -ENOENT; } - firmware = rpi_firmware_get(firmware_node); + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); of_node_put(firmware_node); if (!firmware) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:29 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:29 +0100 Subject: [PATCH v3 03/11] gpio: raspberrypi-exp: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-4-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/gpio/gpio-raspberrypi-exp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index bb100e0124e6..64a552ecc2ad 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -208,7 +208,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:31 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:31 +0100 Subject: [PATCH v3 05/11] soc: bcm: raspberrypi-power: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-6-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/soc/bcm/raspberrypi-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index 5d1aacdd84ef..068715d6e66d 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -177,7 +177,7 @@ static int rpi_power_probe(struct platform_device *pdev) return -ENODEV; } - rpi_domains->fw = rpi_firmware_get(fw_np); + rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np); of_node_put(fw_np); if (!rpi_domains->fw) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:30 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:30 +0100 Subject: [PATCH v3 04/11] reset: raspberrypi: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-5-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/reset/reset-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c index 02f59c06f69b..fa23db554bcf 100644 --- a/drivers/reset/reset-raspberrypi.c +++ b/drivers/reset/reset-raspberrypi.c @@ -82,7 +82,7 @@ static int rpi_reset_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(np); + fw = devm_rpi_firmware_get(&pdev->dev, np); of_node_put(np); if (!fw) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:32 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:32 +0100 Subject: [PATCH v3 06/11] staging: vchiq: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-7-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 01125d9f991b..3c25e237e334 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -2723,7 +2723,7 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOENT; } - drvdata->fw = rpi_firmware_get(fw_node); + drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!drvdata->fw) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:33 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:33 +0100 Subject: [PATCH v3 07/11] input: raspberrypi-ts: Release firmware handle when not needed In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-8-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/input/touchscreen/raspberrypi-ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index ef6aaed217cf..efed0efa91d9 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -134,7 +134,7 @@ static int rpi_ts_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:34 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:34 +0100 Subject: [PATCH v3 08/11] firmware: raspberrypi: Get rid of rpi_firmware_get() In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-9-nsaenzjulienne@suse.de> There a no users left to the function as they all converted to devm_rpi_firmware_get(). Just get rid of it. Signed-off-by: Nicolas Saenz Julienne --- drivers/firmware/raspberrypi.c | 17 ----------------- include/soc/bcm2835/raspberrypi-firmware.h | 6 ------ 2 files changed, 23 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 74bdb3bde9dc..67f7105f3fd2 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -297,23 +297,6 @@ static void rpi_firmware_put(void *data) wake_up(&fw->wait); } -/** - * rpi_firmware_get - Get pointer to rpi_firmware structure. - * @firmware_node: Pointer to the firmware Device Tree node. - * - * Returns NULL is the firmware device is not ready. - */ -struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) -{ - struct platform_device *pdev = of_find_device_by_node(firmware_node); - - if (!pdev) - return NULL; - - return platform_get_drvdata(pdev); -} -EXPORT_SYMBOL_GPL(rpi_firmware_get); - /** * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index 8fe64f53a394..eaa4e516e4c6 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -140,7 +140,6 @@ int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); -struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, struct device_node *firmware_node); #else @@ -156,11 +155,6 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, return -ENOSYS; } -static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) -{ - return NULL; -} - static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, struct device_node *firmware_node) { -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:35 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:35 +0100 Subject: [PATCH v3 09/11] dt-bindings: pwm: Add binding for RPi firmware PWM bus In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-10-nsaenzjulienne@suse.de> The PWM bus controlling the fan in RPi's official PoE hat can only be controlled by the board's co-processor. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Rob Herring --- Changes since v1: - Update bindings to use 2 #pwm-cells .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 +++++++++++++++++++ .../pwm/raspberrypi,firmware-pwm.h | 13 ++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index a2c63c8b1d10..8029ce958c48 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -64,6 +64,21 @@ properties: - compatible - "#reset-cells" + pwm: + type: object + + properties: + compatible: + const: raspberrypi,firmware-pwm + + "#pwm-cells": + # See pwm.yaml in this directory for a description of the cells format. + const: 2 + + required: + - compatible + - "#pwm-cells" + additionalProperties: false required: @@ -87,5 +102,10 @@ examples: compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + pwm: pwm { + compatible = "raspberrypi,firmware-pwm"; + #pwm-cells = <1>; + }; }; ... diff --git a/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h b/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h new file mode 100644 index 000000000000..27c5ce68847b --- /dev/null +++ b/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H + +#define RASPBERRYPI_FIRMWARE_PWM_POE 0 +#define RASPBERRYPI_FIRMWARE_PWM_NUM 1 + +#endif -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:36 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:36 +0100 Subject: [PATCH v3 10/11] DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-11-nsaenzjulienne@suse.de> This is an example on how to enable the fan on top of RPi's official PoE hat. Signed-off-by: Nicolas Saenz Julienne --- Changes since v1: - Update patch to use 2 pwm cells arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 09a1182c2936..361db82619a4 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -5,6 +5,7 @@ #include "bcm283x-rpi-usb-peripheral.dtsi" #include +#include / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; @@ -68,6 +69,54 @@ sd_vcc_reg: sd_vcc_reg { enable-active-high; gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; }; + + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 50 150 255>; + #cooling-cells = <2>; + pwms = <&fwpwm RASPBERRYPI_FIRMWARE_PWM_POE 80000>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + trips { + threshold: trip-point at 0 { + temperature = <45000>; + hysteresis = <5000>; + type = "active"; + }; + + target: trip-point at 1 { + temperature = <50000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_hot: cpu_hot at 0 { + temperature = <55000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&threshold>; + cooling-device = <&fan 0 1>; + }; + + map1 { + trip = <&target>; + cooling-device = <&fan 1 2>; + }; + + map2 { + trip = <&cpu_hot>; + cooling-device = <&fan 2 3>; + }; + }; + }; + }; }; &ddc0 { @@ -103,6 +152,11 @@ reset: reset { compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + fwpwm: pwm { + compatible = "raspberrypi,firmware-pwm"; + #pwm-cells = <2>; + }; }; &gpio { -- 2.29.1 From nsaenzjulienne at suse.de Wed Nov 4 10:39:37 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 4 Nov 2020 11:39:37 +0100 Subject: [PATCH v3 11/11] pwm: Add Raspberry Pi Firmware based PWM bus In-Reply-To: <20201104103938.1286-1-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> Message-ID: <20201104103938.1286-12-nsaenzjulienne@suse.de> Adds support to control the PWM bus available in official Raspberry Pi PoE HAT. Only RPi's co-processor has access to it, so commands have to be sent through RPi's firmware mailbox interface. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get() - Rename driver - Small cleanups as per Andy Shevchenko's comments Changes since v1: - Use default pwm bindings and get rid of xlate() function - Correct spelling errors - Correct apply() function - Round values - Fix divisions in arm32 mode - Small cleanups drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 63be5362fd3a..ab31615f07fc 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -379,6 +379,15 @@ config PWM_PXA To compile this driver as a module, choose M here: the module will be called pwm-pxa. +config PWM_RASPBERRYPI_POE + tristate "Raspberry Pi Firwmware PoE Hat PWM support" + # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only + # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + config PWM_RCAR tristate "Renesas R-Car PWM support" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index cbdcd55d69ee..7ecbbbcb323a 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c new file mode 100644 index 000000000000..91cd826a36f3 --- /dev/null +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020 Nicolas Saenz Julienne + * For more information on Raspberry Pi's PoE hat see: + * https://www.raspberrypi.org/products/poe-hat/ + * + * Limitations: + * - No disable bit, so a disabled PWM is simulated by duty_cycle 0 + * - Only normal polarity + * - Fixed 12.5 kHz period + * + * The current period is completed when HW is reconfigured. + */ + +#include +#include +#include +#include + +#include +#include + +#define RPI_PWM_MAX_DUTY 255 +#define RPI_PWM_PERIOD_NS 80000 /* 12.5 kHz */ + +#define RPI_PWM_CUR_DUTY_REG 0x0 +#define RPI_PWM_DEF_DUTY_REG 0x1 + +struct raspberrypi_pwm { + struct rpi_firmware *firmware; + struct pwm_chip chip; + unsigned int duty_cycle; +}; + +struct raspberrypi_pwm_prop { + __le32 reg; + __le32 val; + __le32 ret; +} __packed; + +static inline struct raspberrypi_pwm *to_raspberrypi_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct raspberrypi_pwm, chip); +} + +static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, + u32 reg, u32 val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = cpu_to_le32(reg), + .val = cpu_to_le32(val), + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + return 0; +} + +static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, + u32 reg, u32 *val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = reg + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + *val = le32_to_cpu(msg.val); + + return 0; +} + +static void raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + + state->period = RPI_PWM_PERIOD_NS; + state->duty_cycle = DIV_ROUND_CLOSEST(rpipwm->duty_cycle * RPI_PWM_PERIOD_NS, + RPI_PWM_MAX_DUTY); + state->enabled = !!(rpipwm->duty_cycle); + state->polarity = PWM_POLARITY_NORMAL; +} + +static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + unsigned int duty_cycle; + int ret; + + if (state->period < RPI_PWM_PERIOD_NS || + state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) + duty_cycle = 0; + else if (state->duty_cycle < RPI_PWM_PERIOD_NS) + duty_cycle = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * RPI_PWM_MAX_DUTY, + RPI_PWM_PERIOD_NS); + else + duty_cycle = RPI_PWM_MAX_DUTY; + + if (duty_cycle == rpipwm->duty_cycle) + return 0; + + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set duty cycle: %d\n", ret); + return ret; + } + + /* + * This sets the default duty cycle after resetting the board, we + * updated it every time to mimic Raspberry Pi's downstream's driver + * behaviour. + */ + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_DEF_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set default duty cycle: %d\n", ret); + return ret; + } + + rpipwm->duty_cycle = duty_cycle; + + return 0; +} + +static const struct pwm_ops raspberrypi_pwm_ops = { + .get_state = raspberrypi_pwm_get_state, + .apply = raspberrypi_pwm_apply, + .owner = THIS_MODULE, +}; + +static int raspberrypi_pwm_probe(struct platform_device *pdev) +{ + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_pwm *rpipwm; + int ret; + + firmware_node = of_get_parent(dev->of_node); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); + of_node_put(firmware_node); + if (!firmware) + return -EPROBE_DEFER; + + rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL); + if (!rpipwm) + return -ENOMEM; + + rpipwm->firmware = firmware; + rpipwm->chip.dev = dev; + rpipwm->chip.ops = &raspberrypi_pwm_ops; + rpipwm->chip.base = -1; + rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; + + platform_set_drvdata(pdev, rpipwm); + + ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + &rpipwm->duty_cycle); + if (ret) { + dev_err(dev, "Failed to get duty cycle: %d\n", ret); + return ret; + } + + return pwmchip_add(&rpipwm->chip); +} + +static int raspberrypi_pwm_remove(struct platform_device *pdev) +{ + struct raspberrypi_pwm *rpipwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&rpipwm->chip); +} + +static const struct of_device_id raspberrypi_pwm_of_match[] = { + { .compatible = "raspberrypi,firmware-pwm", }, + { } +}; +MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match); + +static struct platform_driver raspberrypi_pwm_driver = { + .driver = { + .name = "raspberrypi-pwm", + .of_match_table = raspberrypi_pwm_of_match, + }, + .probe = raspberrypi_pwm_probe, + .remove = raspberrypi_pwm_remove, +}; +module_platform_driver(raspberrypi_pwm_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne "); +MODULE_DESCRIPTION("Raspberry Pi Firwmare Based PWM Bus Driver"); +MODULE_LICENSE("GPL v2"); -- 2.29.1 From paul.kocialkowski at bootlin.com Wed Nov 4 10:48:27 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:48:27 +0100 Subject: [PATCH 07/14] dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation In-Reply-To: <20201027184459.eberpkr52kay3du6@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-8-paul.kocialkowski@bootlin.com> <20201026161450.gr3dqpltxw2ccc3s@gilmour.lan> <20201027095221.GE168350@aptenodytes> <20201027184459.eberpkr52kay3du6@gilmour.lan> Message-ID: <20201104104827.GD285779@aptenodytes> Hi, On Tue 27 Oct 20, 19:44, Maxime Ripard wrote: > On Tue, Oct 27, 2020 at 10:52:21AM +0100, Paul Kocialkowski wrote: > > Hi, > > > > On Mon 26 Oct 20, 17:14, Maxime Ripard wrote: > > > i2c? :) > > > > Oops, good catch! > > > > > On Fri, Oct 23, 2020 at 07:45:39PM +0200, Paul Kocialkowski wrote: > > > > This introduces YAML bindings documentation for the A31 MIPI CSI-2 > > > > controller. > > > > > > > > Signed-off-by: Paul Kocialkowski > > > > --- > > > > .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 ++++++++++++++++++ > > > > 1 file changed, 168 insertions(+) > > > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > > > > > diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > new file mode 100644 > > > > index 000000000000..9adc0bc27033 > > > > --- /dev/null > > > > +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > @@ -0,0 +1,168 @@ > > > > +# SPDX-License-Identifier: GPL-2.0 > > > > +%YAML 1.2 > > > > +--- > > > > +$id: http://devicetree.org/schemas/media/allwinner,sun6i-a31-mipi-csi2.yaml# > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > > > + > > > > +title: Allwinner A31 MIPI CSI-2 Device Tree Bindings > > > > + > > > > +maintainers: > > > > + - Paul Kocialkowski > > > > + > > > > +properties: > > > > + compatible: > > > > + oneOf: > > > > + - const: allwinner,sun6i-a31-mipi-csi2 > > > > + - items: > > > > + - const: allwinner,sun8i-v3s-mipi-csi2 > > > > + - const: allwinner,sun6i-a31-mipi-csi2 > > > > + > > > > + reg: > > > > + maxItems: 1 > > > > + > > > > + interrupts: > > > > + maxItems: 1 > > > > + > > > > + clocks: > > > > + items: > > > > + - description: Bus Clock > > > > + - description: Module Clock > > > > + > > > > + clock-names: > > > > + items: > > > > + - const: bus > > > > + - const: mod > > > > + > > > > + phys: > > > > + items: > > > > + - description: MIPI D-PHY > > > > + > > > > + phy-names: > > > > + items: > > > > + - const: dphy > > > > + > > > > + resets: > > > > + maxItems: 1 > > > > + > > > > + # See ./video-interfaces.txt for details > > > > + ports: > > > > + type: object > > > > + > > > > + properties: > > > > + port at 0: > > > > + type: object > > > > + description: Input port, connect to a MIPI CSI-2 sensor > > > > + > > > > + properties: > > > > + reg: > > > > + const: 0 > > > > + > > > > + endpoint: > > > > + type: object > > > > + > > > > + properties: > > > > + remote-endpoint: true > > > > + > > > > + bus-type: > > > > + const: 4 > > > > + > > > > + clock-lanes: > > > > + maxItems: 1 > > > > + > > > > + data-lanes: > > > > + minItems: 1 > > > > + maxItems: 4 > > > > + > > > > + required: > > > > + - bus-type > > > > + - data-lanes > > > > + - remote-endpoint > > > > + > > > > + additionalProperties: false > > > > + > > > > + required: > > > > + - endpoint > > > > + > > > > + additionalProperties: false > > > > + > > > > + port at 1: > > > > + type: object > > > > + description: Output port, connect to a CSI controller > > > > + > > > > + properties: > > > > + reg: > > > > + const: 1 > > > > + > > > > + endpoint: > > > > + type: object > > > > + > > > > + properties: > > > > + remote-endpoint: true > > > > + > > > > + bus-type: > > > > + const: 4 > > > > > > That one seems a bit weird. If the input and output ports are using the > > > same format, what is that "bridge" supposed to be doing? > > > > Fair enough. What this represents is the internal link (likely a FIFO) between > > the two controllers. It is definitely not a MIPI CSI-2 bus but there's no > > mbus type for an internal link (probably because it's not a bus after all). > > > > Note that on the CSI controller side, we need the bus-type to be set to 4 for it > > to properly select the MIPI CSI-2 input. So it just felt more logical to have > > the same on the other side of the endpoint. On the other hand, we can just > > remove it on the MIPI CSI-2 controller side since it won't check it and have it > > fallback to the unknown mbus type. > > > > But that would make the types inconsistent on the two sides of the link. > > I don't think V4L2 will complain about it at the moment, but it would also make > > sense that it does eventually. > > > > What do you think? > > There's still the same issue though, it doesn't make any sense that a > bridge doesn't change the bus type. If it really did, we wouldn't need > that in the first place. Yes I agreee. > What you want to check in your driver is whether the subdev you're > connected to has a sink pad that uses MIPI-CSI I'm not really sure that's possible, but if it is it would indeed be the most appropriate solution. If it's not, we still need to know that we need to feed from MIPI CSI-2 so I don't see any other option than report MIPI CSI-2 on both ends of MIPI CSI-2 controller. But there's still the question of what media bus type should be reported for the CSI <-> MIPI CSI-2 link. I'm fine with unknown but we could also add a generic internal bus type for this case. Paul > Maxime > > > > > + additionalProperties: false > > > > + > > > > + required: > > > > + - endpoint > > > > + > > > > + additionalProperties: false > > > > + > > > > +required: > > > > + - compatible > > > > + - reg > > > > + - interrupts > > > > + - clocks > > > > + - clock-names > > > > + - resets > > > > + > > > > +additionalProperties: false > > > > + > > > > +examples: > > > > + - | > > > > + #include > > > > + #include > > > > + #include > > > > + > > > > + mipi_csi2: mipi-csi2 at 1cb1000 { > > > > > > The unit name should be pretty standard, with the list here: > > > > > > https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter2-devicetree-basics.rst#generic-names-recommendation > > > > > > there's nothing really standing out for us in that list, but given that > > > there's dsi, we should stick with csi > > > > Then what really surprises me is that the CSI controllers are called "camera", > > not "csi". If "camera" is supposed to cover both image sensor and camera sensor > > interfaces, it would probably fit MIPI CSI-2 as well. > > > > I see lots of names with -controller for controllers with specific devices > > attached, like "nand-controller" or "lcd-controller". Maybe using > > "camera-controller" for the CSI and MIPI CSI-2 controllers would make the most > > sense, while keeping "camera" for the actual image sensors. > > > > What do you think? > > If you really want to discuss this, feel free to open a PR for the DT > spec and add it. However, I still think this csi would be best here: > it's neither a camera nor a camera controller > > maxime -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From abbotti at mev.co.uk Wed Nov 4 10:49:18 2020 From: abbotti at mev.co.uk (Ian Abbott) Date: Wed, 4 Nov 2020 10:49:18 +0000 Subject: [PATCH] staging: comedi: cb_pcidas: reinstate delay removed from trimpot setting In-Reply-To: References: <20201029141833.126856-1-abbotti@mev.co.uk> <3d7cf15a-c389-ec2c-5e29-8838e8466790@mev.co.uk> Message-ID: <975358e2-6a08-211a-d232-3cd0ce628e8e@mev.co.uk> On 02/11/2020 11:16, Ian Abbott wrote: > On 02/11/2020 10:25, Ian Abbott wrote: >> On 29/10/2020 14:18, Ian Abbott wrote: >>> Commit eddd2a4c675c ("staging: comedi: cb_pcidas: refactor >>> write_calibration_bitstream()") inadvertently removed one of the >>> `udelay(1)` calls when writing to the calibration register in >>> `cb_pcidas_calib_write()`.? Reinstate the delay.? It may seem strange >>> that the delay is placed before the register write, but this function is >>> called in a loop so the extra delay can make a difference. >>> >>> This _might_ solve reported issues reading analog inputs on a >>> PCIe-DAS1602/16 card where the analog input values "were scaled in a >>> strange way that didn't make sense".? On the same hardware running a >>> system with a 3.13 kernel, and then a system with a 4.4 kernel, but with >>> the same application software, the system with the 3.13 kernel was fine, >>> but the one with the 4.4 kernel exhibited the problem.? Of the 90 >>> changes to the driver between those kernel versions, this change looked >>> like the most likely culprit. >> >> Actually, I've realized that this patch will have no effect on the >> PCIe-DAS1602/16 card because it uses a different driver - cb_pcimdas, >> not cb_pcidas. > > But that's also confusing because PCIe-DAS1602/16 was not supported > until the 3.19 kernel!? I know the reported has both PCI-DAS1602/16 and > PCIe-DAS1602/16 cards (supported by cb_pcidas and cb_pcimdas > respectively), so there could have been some mix-up in the reporting. Mystery solved. The reporter had a mixture of PCIe-DAS1602/16 and PCIM-DAS1602/16 cards (not PCI-DAS1602/16). Both of those are supported by the "cb_pcimdas" driver (not "cb_pcidas"), although the PCIe card was not supported until the 3.19 kernel (by commit 4e3d14af1286). Testing with the 3.13 kernel was done with the PCIM card. The "strange scaling" was due to a change in the ranges reported for the analog input subdevice in the 4.1 kernel (by commit c7549d770a27). Before then, it just reported a single dummy range [0, 1000000] with no units (converted to [0.0, 1.0] with no units by comedilib). Afterwards, it reported four different voltage ranges (either unipolar or bipolar, depending in a status bit tied to a physical switch). The reporter's application code was using the reported range to scale the raw values to a voltage (using comedilib functions), but because the reported range was bogus, the application code was performing additional scaling (outside of comedilib). The application code can be changed to check whether the device is reporting a proper voltage range or the old, bogus range, and behave accordingly. >> Greg, you might as well drop this patch if you haven't already applied >> it, since it was only a hunch that it fixed a problem. That's still the case, although it won't do any harm if applied (apart from the incorrect patch description). -- -=( Ian Abbott || MEV Ltd. is a company )=- -=( registered in England & Wales. Regd. number: 02862268. )=- -=( Regd. addr.: S11 & 12 Building 67, Europa Business Park, )=- -=( Bird Hall Lane, STOCKPORT, SK3 0XA, UK. || www.mev.co.uk )=- From paul.kocialkowski at bootlin.com Wed Nov 4 10:53:34 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:53:34 +0100 Subject: [PATCH 02/14] phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI CSI-2 In-Reply-To: <20201027182811.j6372vdmls5yvhri@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-3-paul.kocialkowski@bootlin.com> <20201026153857.iwkn4iusi2jy2yf4@gilmour.lan> <20201027092326.GB168350@aptenodytes> <20201027182811.j6372vdmls5yvhri@gilmour.lan> Message-ID: <20201104105334.GE285779@aptenodytes> Hi, On Tue 27 Oct 20, 19:28, Maxime Ripard wrote: > > Hi, > > On Tue, Oct 27, 2020 at 10:23:26AM +0100, Paul Kocialkowski wrote: > > On Mon 26 Oct 20, 16:38, Maxime Ripard wrote: > > > On Fri, Oct 23, 2020 at 07:45:34PM +0200, Paul Kocialkowski wrote: > > > > The Allwinner A31 D-PHY supports both Rx and Tx modes. While the latter > > > > is already supported and used for MIPI DSI this adds support for the > > > > former, to be used with MIPI CSI-2. > > > > > > > > This implementation is inspired by the Allwinner BSP implementation. > > > > > > Mentionning which BSP you took this from would be helpful > > > > Sure! It's from the Github repo linked from https://linux-sunxi.org/V3s. > > Would you like that I mention this URL explicitly or would it be enough to > > mention "Allwinner's V3s Linux SDK" as they seem to call it? > > Yeah, that would be great > > > > +static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy) > > > > +{ > > > > + /* Physical clock rate is actually half of symbol rate with DDR. */ > > > > + unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; > > > > + unsigned long dphy_clk_rate; > > > > + unsigned int rx_dly; > > > > + unsigned int lprst_dly; > > > > + u32 value; > > > > + > > > > + dphy_clk_rate = clk_get_rate(dphy->mod_clk); > > > > + if (!dphy_clk_rate) > > > > + return -1; > > > > > > Returning -1 is weird here? > > > > What do you think would be a more appropriate error code to return? > > It looks like some other drivers return -EINVAL when that happens (but many > > don't do the check). > > Yeah, EINVAL at least is better than ENOPERM > > > > > + > > > > + /* Hardcoded timing parameters from the Allwinner BSP. */ > > > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG, > > > > + SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(255) | > > > > + SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(255) | > > > > + SUN6I_DPHY_RX_TIME0_LP_RX(255)); > > > > + > > > > + /* > > > > + * Formula from the Allwinner BSP, with hardcoded coefficients > > > > + * (probably internal divider/multiplier). > > > > + */ > > > > + rx_dly = 8 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 8)); > > > > + > > > > + /* > > > > + * The Allwinner BSP has an alternative formula for LP_RX_ULPS_WP: > > > > + * lp_ulps_wp_cnt = lp_ulps_wp_ms * lp_clk / 1000 > > > > + * but does not use it and hardcodes 255 instead. > > > > + */ > > > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG, > > > > + SUN6I_DPHY_RX_TIME1_RX_DLY(rx_dly) | > > > > + SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(255)); > > > > + > > > > + /* HS_RX_ANA0 value is hardcoded in the Allwinner BSP. */ > > > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG, > > > > + SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(4)); > > > > + > > > > + /* > > > > + * Formula from the Allwinner BSP, with hardcoded coefficients > > > > + * (probably internal divider/multiplier). > > > > + */ > > > > + lprst_dly = 4 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 2)); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG, > > > > + SUN6I_DPHY_RX_TIME3_LPRST_DLY(lprst_dly)); > > > > + > > > > + /* Analog parameters are hardcoded in the Allwinner BSP. */ > > > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, > > > > + SUN6I_DPHY_ANA0_REG_PWS | > > > > + SUN6I_DPHY_ANA0_REG_SLV(7) | > > > > + SUN6I_DPHY_ANA0_REG_SFB(2)); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, > > > > + SUN6I_DPHY_ANA1_REG_SVTT(4)); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, > > > > + SUN6I_DPHY_ANA4_REG_DMPLVC | > > > > + SUN6I_DPHY_ANA4_REG_DMPLVD(1)); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, > > > > + SUN6I_DPHY_ANA2_REG_ENIB); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, > > > > + SUN6I_DPHY_ANA3_EN_LDOR | > > > > + SUN6I_DPHY_ANA3_EN_LDOC | > > > > + SUN6I_DPHY_ANA3_EN_LDOD); > > > > + > > > > + /* > > > > + * Delay comes from the Allwinner BSP, likely for internal regulator > > > > + * ramp-up. > > > > + */ > > > > + udelay(3); > > > > + > > > > + value = SUN6I_DPHY_RX_CTL_EN_DBC | SUN6I_DPHY_RX_CTL_RX_CLK_FORCE; > > > > + > > > > + /* > > > > + * Rx data lane force-enable bits are used as regular RX enable by the > > > > + * Allwinner BSP. > > > > + */ > > > > + if (dphy->config.lanes >= 1) > > > > + value |= SUN6I_DPHY_RX_CTL_RX_D0_FORCE; > > > > + if (dphy->config.lanes >= 2) > > > > + value |= SUN6I_DPHY_RX_CTL_RX_D1_FORCE; > > > > + if (dphy->config.lanes >= 3) > > > > + value |= SUN6I_DPHY_RX_CTL_RX_D2_FORCE; > > > > + if (dphy->config.lanes == 4) > > > > + value |= SUN6I_DPHY_RX_CTL_RX_D3_FORCE; > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value); > > > > + > > > > + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, > > > > + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | > > > > + SUN6I_DPHY_GCTL_EN); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int sun6i_dphy_power_on(struct phy *phy) > > > > +{ > > > > + struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > > > + > > > > + switch (dphy->submode) { > > > > + case PHY_MIPI_DPHY_SUBMODE_TX: > > > > + return sun6i_dphy_tx_power_on(dphy); > > > > + case PHY_MIPI_DPHY_SUBMODE_RX: > > > > + return sun6i_dphy_rx_power_on(dphy); > > > > + default: > > > > + return -EINVAL; > > > > + } > > > > +} > > > > + > > > > > > Can one call power_on before set_mode? > > > > I didn't find anything indicating this is illegal. What would happen here is > > that the D-PHY would be configured to PHY_MIPI_DPHY_SUBMODE_TX (submode == 0) > > at power-on if set_mode is not called before. > > > > I think it's fair to expect that it's too late to change the mode once the PHY > > was powered on. Maybe we should return -EBUSY on set_mode when power on was > > already requested? > > Or maybe we can just clarify it in the framework/function documentation Agreed, I'll add a patch in that direction. I would also be tempted to check on phy->power_count to return -EBUSY in phy_set_mode_ext so that the behavior is enforced. What do you think? Cheers, Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 10:54:59 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:54:59 +0100 Subject: [PATCH 02/14] phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI CSI-2 In-Reply-To: <5df82a6c-daa3-8e47-b7a4-85da60b87dd2@collabora.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-3-paul.kocialkowski@bootlin.com> <5df82a6c-daa3-8e47-b7a4-85da60b87dd2@collabora.com> Message-ID: <20201104105459.GF285779@aptenodytes> Hi Helen and thanks for the review, On Fri 30 Oct 20, 19:44, Helen Koike wrote: > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > The Allwinner A31 D-PHY supports both Rx and Tx modes. While the latter > > is already supported and used for MIPI DSI this adds support for the > > former, to be used with MIPI CSI-2. > > > > This implementation is inspired by the Allwinner BSP implementation. > > > > Signed-off-by: Paul Kocialkowski > > --- > > drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 +++++++++++++++++++- > > 1 file changed, 160 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c > > index 1fa761ba6cbb..8bcd4bb79f60 100644 > > --- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c > > +++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c > > @@ -24,6 +24,14 @@ > > #define SUN6I_DPHY_TX_CTL_REG 0x04 > > #define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) > > > > +#define SUN6I_DPHY_RX_CTL_REG 0x08 > > +#define SUN6I_DPHY_RX_CTL_EN_DBC BIT(31) > > +#define SUN6I_DPHY_RX_CTL_RX_CLK_FORCE BIT(24) > > +#define SUN6I_DPHY_RX_CTL_RX_D3_FORCE BIT(23) > > +#define SUN6I_DPHY_RX_CTL_RX_D2_FORCE BIT(22) > > +#define SUN6I_DPHY_RX_CTL_RX_D1_FORCE BIT(21) > > +#define SUN6I_DPHY_RX_CTL_RX_D0_FORCE BIT(20) > > + > > #define SUN6I_DPHY_TX_TIME0_REG 0x10 > > #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) > > #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) > > @@ -44,12 +52,29 @@ > > #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) > > #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) > > > > +#define SUN6I_DPHY_RX_TIME0_REG 0x30 > > +#define SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(n) (((n) & 0xff) << 24) > > +#define SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(n) (((n) & 0xff) << 16) > > +#define SUN6I_DPHY_RX_TIME0_LP_RX(n) (((n) & 0xff) << 8) > > + > > +#define SUN6I_DPHY_RX_TIME1_REG 0x34 > > +#define SUN6I_DPHY_RX_TIME1_RX_DLY(n) (((n) & 0xfff) << 20) > > +#define SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(n) ((n) & 0xfffff) > > + > > +#define SUN6I_DPHY_RX_TIME2_REG 0x38 > > +#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA1(n) (((n) & 0xff) << 8) > > +#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(n) ((n) & 0xff) > > + > > +#define SUN6I_DPHY_RX_TIME3_REG 0x40 > > +#define SUN6I_DPHY_RX_TIME3_LPRST_DLY(n) (((n) & 0xffff) << 16) > > + > > #define SUN6I_DPHY_ANA0_REG 0x4c > > #define SUN6I_DPHY_ANA0_REG_PWS BIT(31) > > #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) > > #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) > > #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) > > #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) > > +#define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2) > > > > #define SUN6I_DPHY_ANA1_REG 0x50 > > #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) > > @@ -92,6 +117,8 @@ struct sun6i_dphy { > > > > struct phy *phy; > > struct phy_configure_opts_mipi_dphy config; > > + > > + int submode; > > }; > > > > static int sun6i_dphy_init(struct phy *phy) > > @@ -105,6 +132,18 @@ static int sun6i_dphy_init(struct phy *phy) > > return 0; > > } > > > > +static int sun6i_dphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) > > +{ > > + struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > + > > + if (mode != PHY_MODE_MIPI_DPHY) > > + return -EINVAL; > > + > > + dphy->submode = submode; > > Shouldn't you check if the submode is valid here? Yes that's a good point, thanks! > > + > > + return 0; > > +} > > + > > static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) > > { > > struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > @@ -119,9 +158,8 @@ static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) > > return 0; > > } > > > > -static int sun6i_dphy_power_on(struct phy *phy) > > +static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) > > { > > - struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); > > > > regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, > > @@ -211,12 +249,129 @@ static int sun6i_dphy_power_on(struct phy *phy) > > return 0; > > } > > > > +static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy) > > +{ > > + /* Physical clock rate is actually half of symbol rate with DDR. */ > > + unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; > > + unsigned long dphy_clk_rate; > > + unsigned int rx_dly; > > + unsigned int lprst_dly; > > + u32 value; > > + > > + dphy_clk_rate = clk_get_rate(dphy->mod_clk); > > + if (!dphy_clk_rate) > > + return -1; > > + > > + /* Hardcoded timing parameters from the Allwinner BSP. */ > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG, > > + SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(255) | > > + SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(255) | > > + SUN6I_DPHY_RX_TIME0_LP_RX(255)); > > + > > + /* > > + * Formula from the Allwinner BSP, with hardcoded coefficients > > + * (probably internal divider/multiplier). > > + */ > > + rx_dly = 8 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 8)); > > + > > + /* > > + * The Allwinner BSP has an alternative formula for LP_RX_ULPS_WP: > > + * lp_ulps_wp_cnt = lp_ulps_wp_ms * lp_clk / 1000 > > + * but does not use it and hardcodes 255 instead. > > + */ > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG, > > + SUN6I_DPHY_RX_TIME1_RX_DLY(rx_dly) | > > + SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(255)); > > + > > + /* HS_RX_ANA0 value is hardcoded in the Allwinner BSP. */ > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG, > > + SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(4)); > > + > > + /* > > + * Formula from the Allwinner BSP, with hardcoded coefficients > > + * (probably internal divider/multiplier). > > + */ > > + lprst_dly = 4 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 2)); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG, > > + SUN6I_DPHY_RX_TIME3_LPRST_DLY(lprst_dly)); > > + > > + /* Analog parameters are hardcoded in the Allwinner BSP. */ > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, > > + SUN6I_DPHY_ANA0_REG_PWS | > > + SUN6I_DPHY_ANA0_REG_SLV(7) | > > + SUN6I_DPHY_ANA0_REG_SFB(2)); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, > > + SUN6I_DPHY_ANA1_REG_SVTT(4)); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, > > + SUN6I_DPHY_ANA4_REG_DMPLVC | > > + SUN6I_DPHY_ANA4_REG_DMPLVD(1)); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, > > + SUN6I_DPHY_ANA2_REG_ENIB); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, > > + SUN6I_DPHY_ANA3_EN_LDOR | > > + SUN6I_DPHY_ANA3_EN_LDOC | > > + SUN6I_DPHY_ANA3_EN_LDOD); > > + > > + /* > > + * Delay comes from the Allwinner BSP, likely for internal regulator > > + * ramp-up. > > + */ > > + udelay(3); > > + > > + value = SUN6I_DPHY_RX_CTL_EN_DBC | SUN6I_DPHY_RX_CTL_RX_CLK_FORCE; > > + > > + /* > > + * Rx data lane force-enable bits are used as regular RX enable by the > > + * Allwinner BSP. > > + */ > > + if (dphy->config.lanes >= 1) > > + value |= SUN6I_DPHY_RX_CTL_RX_D0_FORCE; > > + if (dphy->config.lanes >= 2) > > + value |= SUN6I_DPHY_RX_CTL_RX_D1_FORCE; > > + if (dphy->config.lanes >= 3) > > + value |= SUN6I_DPHY_RX_CTL_RX_D2_FORCE; > > + if (dphy->config.lanes == 4) > > + value |= SUN6I_DPHY_RX_CTL_RX_D3_FORCE; > > I would replace this by a switch case with fallthrough to avoid too many comparisons > to the same value. Okay, why not! Cheers, Paul > Regards, > Helen > > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, > > + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | > > + SUN6I_DPHY_GCTL_EN); > > + > > + return 0; > > +} > > + > > +static int sun6i_dphy_power_on(struct phy *phy) > > +{ > > + struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > + > > + switch (dphy->submode) { > > + case PHY_MIPI_DPHY_SUBMODE_TX: > > + return sun6i_dphy_tx_power_on(dphy); > > + case PHY_MIPI_DPHY_SUBMODE_RX: > > + return sun6i_dphy_rx_power_on(dphy); > > + default: > > + return -EINVAL; > > + } > > +} > > + > > static int sun6i_dphy_power_off(struct phy *phy) > > { > > struct sun6i_dphy *dphy = phy_get_drvdata(phy); > > > > - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, > > - SUN6I_DPHY_ANA1_REG_VTTMODE, 0); > > + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0); > > + > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0); > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0); > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0); > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0); > > + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0); > > > > return 0; > > } > > @@ -234,6 +389,7 @@ static int sun6i_dphy_exit(struct phy *phy) > > > > > > static const struct phy_ops sun6i_dphy_ops = { > > + .set_mode = sun6i_dphy_set_mode, > > .configure = sun6i_dphy_configure, > > .power_on = sun6i_dphy_power_on, > > .power_off = sun6i_dphy_power_off, > > -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 10:56:19 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 11:56:19 +0100 Subject: [PATCH 04/14] media: sun6i-csi: Fix the image storage bpp for 10/12-bit Bayer formats In-Reply-To: <60fc4f85-e08f-fec6-5687-005add5cbeed@collabora.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-5-paul.kocialkowski@bootlin.com> <60fc4f85-e08f-fec6-5687-005add5cbeed@collabora.com> Message-ID: <20201104105619.GG285779@aptenodytes> Hi Helen, On Fri 30 Oct 20, 19:45, Helen Koike wrote: > Hi Paul, > > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > Both 10 and 12-bit Bayer formats are stored aligned as 16-bit values > > in memory, not unaligned 10 or 12 bits. > > > > Since the current code for retreiving the bpp is used only to > > calculate the memory storage size of the picture (which is what > > pixel formats describe, unlike media bus formats), fix it there. > > > > Fixes: 5cc7522d8965 ("media: sun6i: Add support for Allwinner CSI V3s") > > Co-developed-by: K?vin L'h?pital > > Signed-off-by: K?vin L'h?pital > > Signed-off-by: Paul Kocialkowski > > --- > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 20 +++++++++---------- > > 1 file changed, 10 insertions(+), 10 deletions(-) > > > > diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h > > index c626821aaedb..7f2be70ae641 100644 > > --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h > > +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h > > @@ -86,7 +86,7 @@ void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr); > > */ > > void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable); > > > > -/* get bpp form v4l2 pixformat */ > > +/* get memory storage bpp from v4l2 pixformat */ > > static inline int sun6i_csi_get_bpp(unsigned int pixformat) > > { > > switch (pixformat) { > > @@ -96,15 +96,6 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat) > > case V4L2_PIX_FMT_SRGGB8: > > case V4L2_PIX_FMT_JPEG: > > return 8; > > - case V4L2_PIX_FMT_SBGGR10: > > - case V4L2_PIX_FMT_SGBRG10: > > - case V4L2_PIX_FMT_SGRBG10: > > - case V4L2_PIX_FMT_SRGGB10: > > - return 10; > > - case V4L2_PIX_FMT_SBGGR12: > > - case V4L2_PIX_FMT_SGBRG12: > > - case V4L2_PIX_FMT_SGRBG12: > > - case V4L2_PIX_FMT_SRGGB12: > > case V4L2_PIX_FMT_HM12: > > case V4L2_PIX_FMT_NV12: > > case V4L2_PIX_FMT_NV21: > > @@ -121,6 +112,15 @@ static inline int sun6i_csi_get_bpp(unsigned int pixformat) > > case V4L2_PIX_FMT_RGB565: > > case V4L2_PIX_FMT_RGB565X: > > return 16; > > + case V4L2_PIX_FMT_SBGGR10: > > + case V4L2_PIX_FMT_SGBRG10: > > + case V4L2_PIX_FMT_SGRBG10: > > + case V4L2_PIX_FMT_SRGGB10: > > + case V4L2_PIX_FMT_SBGGR12: > > + case V4L2_PIX_FMT_SGBRG12: > > + case V4L2_PIX_FMT_SGRBG12: > > + case V4L2_PIX_FMT_SRGGB12: > > + return 16; > > case V4L2_PIX_FMT_RGB24: > > case V4L2_PIX_FMT_BGR24: > > return 24; > > > > Instead of updating this table, how about using v4l2_format_info() instead? Yes that would be a very good thing to do indeed! Thanks, Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 11:11:37 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 12:11:37 +0100 Subject: [PATCH 00/14] Allwinner MIPI CSI-2 support for A31/V3s/A83T In-Reply-To: References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> Message-ID: <20201104111137.GH285779@aptenodytes> Hi Helen, On Fri 30 Oct 20, 19:44, Helen Koike wrote: > Hi Paul, > > I have some comments through the series, I hope this helps. Thanks for your comments :) > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > This series introduces support for MIPI CSI-2, with the A31 controller that is > > found on most SoCs (A31, V3s and probably V5) as well as the A83T-specific > > controller. While the former uses the same MIPI D-PHY that is already supported > > for DSI, the latter embeds its own D-PHY. > > > > In order to distinguish the use of the D-PHY between Rx mode (for MIPI CSI-2) > > and Tx mode (for MIPI DSI), a submode is introduced for D-PHY in the PHY API. > > This allows adding Rx support in the A31 D-PHY driver. > > > > A few changes and fixes are applied to the A31 CSI controller driver, in order > > to support the MIPI CSI-2 use-case. > > > > Follows is the V4L2 device topology representing the interactions between > > the MIPI CSI-2 sensor, the MIPI CSI-2 controller (which controls the D-PHY) > > and the CSI controller: > > - entity 1: sun6i-csi (1 pad, 1 link) > > type Node subtype V4L flags 0 > > device node name /dev/video0 > > pad0: Sink > > <- "sun6i-mipi-csi2":1 [ENABLED,IMMUTABLE] > > > > - entity 5: sun6i-mipi-csi2 (2 pads, 2 links) > > type V4L2 subdev subtype Unknown flags 0 > > pad0: Sink > > <- "ov5648 0-0036":0 [ENABLED,IMMUTABLE] > > pad1: Source > > -> "sun6i-csi":0 [ENABLED,IMMUTABLE] > > > > - entity 8: ov5648 0-0036 (1 pad, 1 link) > > type V4L2 subdev subtype Sensor flags 0 > > device node name /dev/v4l-subdev0 > > Question: I noticed is that sun6i-mipi-csi2 doesn't expose a node under /dev/, but the sensor > exposes it. Probably because it uses V4L2_SUBDEV_FL_HAS_DEVNODE and sun6i-csi() calls > v4l2_device_register_subdev_nodes(). > > I find this weird from a userspace pov, since usually we don't mix manual and auto propagation > of the configs, so I started wondering if sun6i-csi driver should be calling > v4l2_device_register_subdev_nodes() in the first place. I must admit that I didn't really pay attention to that, but since sun6i-mipi-csi2 is basically a bridge driver, it doesn't make sense to apply manual configuration to it. It is actually designed to forward most subdev ops to its own subdev so configuring it manually would actually result in configuring the sensor. XXX > Also, sun6i-csi doesn't seem to be used by any board dts (it's declared on the dtsi, but I > didn't find any dts enabling it), so I wonder if it would be a bad thing if we update it. > > > pad0: Source > > [fmt:SBGGR8_1X8/640x480 at 1/30 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range] > > -> "sun6i-mipi-csi2":0 [ENABLED,IMMUTABLE] > > If I understand correctly, this is very similar to ipu3: > sensor->bus->dma_engine > > in the case of ipu3-cio2: > sensor->ipu3-csi2->ipu3-cio2 > > in this case: > ov5648->sun6i-mipi-csi2->sun6i-csi Yes this is the correct picture. > On thing that is confusing me is the name csi2 with csi (that makes me think of csi > version one, which is not the case), I would rename it to sun6i-video (or maybe > it is just me who gets confused). So the CSI name comes from the Allwinner litterature and implementation for that controller. Since it supports parallel input on its own, it does in fact support parallel CSI. The DMA engine part alone from that controller is also used for MIPI CSI-2, so in this case the name looses its relevance. > I know this driver is already upstream and not part of this series, but on the other hand it > doesn't seem to be used. Personally I don't find a rename to be necessary and while I agree that nothing would apparently prevent us from renaming it, I would prefer to keep the naming in line with Allwinner's litterature. > On another note, I always wonder if we should expose the bus in the topology, I'm not > sure if it provides any useful API or information for userspace, and you could have > a cleaner code (maybe code could be under phy subsystem). But at the same time, it > seems this is a pattern on v4l2. > > I'd like to hear what others think on the above. My view on this is that we are dealing with two distinct controllers here, one that acts as a DMA engine and one that acts as a bridge. As a result, two chained subdevs looks like the most appropriate representation to me. Using the PHY subsystem would probably be abusing the framework since the MIPI CSI-2 controller is not a PHY (and we do have a D-PHY driver for the D-PHY part that uses the PHY API already). So tl;dr I don't agree that it would be cleaner. Cheers, Paul > > Happy reviewing! > > > > Paul Kocialkowski (14): > > phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes > > phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI > > CSI-2 > > media: sun6i-csi: Support an optional dedicated memory pool > > media: sun6i-csi: Fix the image storage bpp for 10/12-bit Bayer > > formats > > media: sun6i-csi: Only configure the interface data width for parallel > > media: sun6i-csi: Support feeding from the MIPI CSI-2 controller > > dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation > > media: sunxi: Add support for the A31 MIPI CSI-2 controller > > ARM: dts: sun8i: v3s: Add CSI0 camera interface node > > ARM: dts: sun8i: v3s: Add MIPI D-PHY and MIPI CSI-2 interface nodes > > dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation > > media: sunxi: Add support for the A83T MIPI CSI-2 controller > > ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node > > media: sunxi: sun8i-a83t-mipi-csi2: Avoid using the (unsolicited) > > interrupt > > > > .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 +++++ > > .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 +++++ > > arch/arm/boot/dts/sun8i-a83t.dtsi | 26 + > > arch/arm/boot/dts/sun8i-v3s.dtsi | 62 ++ > > drivers/media/platform/sunxi/Kconfig | 2 + > > drivers/media/platform/sunxi/Makefile | 2 + > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 54 +- > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 20 +- > > .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > > .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 +++++++++++++++++ > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 +++ > > .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + > > .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + > > .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ > > .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ > > .../sun8i_a83t_mipi_csi2.c | 660 ++++++++++++++++++ > > .../sun8i_a83t_mipi_csi2.h | 196 ++++++ > > drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 ++++- > > drivers/staging/media/rkisp1/rkisp1-isp.c | 3 +- > > include/linux/phy/phy-mipi-dphy.h | 13 + > > 21 files changed, 2408 insertions(+), 32 deletions(-) > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h > > -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 11:14:46 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 12:14:46 +0100 Subject: [PATCH 00/14] Allwinner MIPI CSI-2 support for A31/V3s/A83T In-Reply-To: <20201104111137.GH285779@aptenodytes> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201104111137.GH285779@aptenodytes> Message-ID: <20201104111446.GA287014@aptenodytes> Hi again, On Wed 04 Nov 20, 12:11, Paul Kocialkowski wrote: > Hi Helen, > > On Fri 30 Oct 20, 19:44, Helen Koike wrote: > > Hi Paul, > > > > I have some comments through the series, I hope this helps. > > Thanks for your comments :) > > > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > > This series introduces support for MIPI CSI-2, with the A31 controller that is > > > found on most SoCs (A31, V3s and probably V5) as well as the A83T-specific > > > controller. While the former uses the same MIPI D-PHY that is already supported > > > for DSI, the latter embeds its own D-PHY. > > > > > > In order to distinguish the use of the D-PHY between Rx mode (for MIPI CSI-2) > > > and Tx mode (for MIPI DSI), a submode is introduced for D-PHY in the PHY API. > > > This allows adding Rx support in the A31 D-PHY driver. > > > > > > A few changes and fixes are applied to the A31 CSI controller driver, in order > > > to support the MIPI CSI-2 use-case. > > > > > > Follows is the V4L2 device topology representing the interactions between > > > the MIPI CSI-2 sensor, the MIPI CSI-2 controller (which controls the D-PHY) > > > and the CSI controller: > > > - entity 1: sun6i-csi (1 pad, 1 link) > > > type Node subtype V4L flags 0 > > > device node name /dev/video0 > > > pad0: Sink > > > <- "sun6i-mipi-csi2":1 [ENABLED,IMMUTABLE] > > > > > > - entity 5: sun6i-mipi-csi2 (2 pads, 2 links) > > > type V4L2 subdev subtype Unknown flags 0 > > > pad0: Sink > > > <- "ov5648 0-0036":0 [ENABLED,IMMUTABLE] > > > pad1: Source > > > -> "sun6i-csi":0 [ENABLED,IMMUTABLE] > > > > > > - entity 8: ov5648 0-0036 (1 pad, 1 link) > > > type V4L2 subdev subtype Sensor flags 0 > > > device node name /dev/v4l-subdev0 > > > > Question: I noticed is that sun6i-mipi-csi2 doesn't expose a node under /dev/, but the sensor > > exposes it. Probably because it uses V4L2_SUBDEV_FL_HAS_DEVNODE and sun6i-csi() calls > > v4l2_device_register_subdev_nodes(). > > > > I find this weird from a userspace pov, since usually we don't mix manual and auto propagation > > of the configs, so I started wondering if sun6i-csi driver should be calling > > v4l2_device_register_subdev_nodes() in the first place. > > I must admit that I didn't really pay attention to that, but since > sun6i-mipi-csi2 is basically a bridge driver, it doesn't make sense to apply > manual configuration to it. It is actually designed to forward most subdev ops > to its own subdev so configuring it manually would actually result in > configuring the sensor. > > XXX Hum, I meant to add something here and then forgot. I'm pretty new to auto vs manual propagation so I don't really have a clear opinion on this and whether we should consider removing the sensor /dev node as well. I'm satisfied with the way things are currently, but it might be due to my own ignorance. Paul > > Also, sun6i-csi doesn't seem to be used by any board dts (it's declared on the dtsi, but I > > didn't find any dts enabling it), so I wonder if it would be a bad thing if we update it. > > > > > pad0: Source > > > [fmt:SBGGR8_1X8/640x480 at 1/30 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range] > > > -> "sun6i-mipi-csi2":0 [ENABLED,IMMUTABLE] > > > > If I understand correctly, this is very similar to ipu3: > > sensor->bus->dma_engine > > > > in the case of ipu3-cio2: > > sensor->ipu3-csi2->ipu3-cio2 > > > > in this case: > > ov5648->sun6i-mipi-csi2->sun6i-csi > > Yes this is the correct picture. > > > On thing that is confusing me is the name csi2 with csi (that makes me think of csi > > version one, which is not the case), I would rename it to sun6i-video (or maybe > > it is just me who gets confused). > > So the CSI name comes from the Allwinner litterature and implementation for that > controller. Since it supports parallel input on its own, it does in fact support > parallel CSI. The DMA engine part alone from that controller is also used for > MIPI CSI-2, so in this case the name looses its relevance. > > > I know this driver is already upstream and not part of this series, but on the other hand it > > doesn't seem to be used. > > Personally I don't find a rename to be necessary and while I agree that > nothing would apparently prevent us from renaming it, I would prefer to keep > the naming in line with Allwinner's litterature. > > > On another note, I always wonder if we should expose the bus in the topology, I'm not > > sure if it provides any useful API or information for userspace, and you could have > > a cleaner code (maybe code could be under phy subsystem). But at the same time, it > > seems this is a pattern on v4l2. > > > > I'd like to hear what others think on the above. > > My view on this is that we are dealing with two distinct controllers here, > one that acts as a DMA engine and one that acts as a bridge. As a result, two > chained subdevs looks like the most appropriate representation to me. > > Using the PHY subsystem would probably be abusing the framework since the > MIPI CSI-2 controller is not a PHY (and we do have a D-PHY driver for the D-PHY > part that uses the PHY API already). > > So tl;dr I don't agree that it would be cleaner. > > Cheers, > > Paul > > > > Happy reviewing! > > > > > > Paul Kocialkowski (14): > > > phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes > > > phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI > > > CSI-2 > > > media: sun6i-csi: Support an optional dedicated memory pool > > > media: sun6i-csi: Fix the image storage bpp for 10/12-bit Bayer > > > formats > > > media: sun6i-csi: Only configure the interface data width for parallel > > > media: sun6i-csi: Support feeding from the MIPI CSI-2 controller > > > dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation > > > media: sunxi: Add support for the A31 MIPI CSI-2 controller > > > ARM: dts: sun8i: v3s: Add CSI0 camera interface node > > > ARM: dts: sun8i: v3s: Add MIPI D-PHY and MIPI CSI-2 interface nodes > > > dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation > > > media: sunxi: Add support for the A83T MIPI CSI-2 controller > > > ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node > > > media: sunxi: sun8i-a83t-mipi-csi2: Avoid using the (unsolicited) > > > interrupt > > > > > > .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 +++++ > > > .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 +++++ > > > arch/arm/boot/dts/sun8i-a83t.dtsi | 26 + > > > arch/arm/boot/dts/sun8i-v3s.dtsi | 62 ++ > > > drivers/media/platform/sunxi/Kconfig | 2 + > > > drivers/media/platform/sunxi/Makefile | 2 + > > > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 54 +- > > > .../platform/sunxi/sun6i-csi/sun6i_csi.h | 20 +- > > > .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > > > .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 +++++++++++++++++ > > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 +++ > > > .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + > > > .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + > > > .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ > > > .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ > > > .../sun8i_a83t_mipi_csi2.c | 660 ++++++++++++++++++ > > > .../sun8i_a83t_mipi_csi2.h | 196 ++++++ > > > drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 ++++- > > > drivers/staging/media/rkisp1/rkisp1-isp.c | 3 +- > > > include/linux/phy/phy-mipi-dphy.h | 13 + > > > 21 files changed, 2408 insertions(+), 32 deletions(-) > > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c > > > create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h > > > > > -- > Paul Kocialkowski, Bootlin > Embedded Linux and kernel engineering > https://bootlin.com -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 11:17:10 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 12:17:10 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201102092110.ro6a456lvbrktwoz@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> <20201102092110.ro6a456lvbrktwoz@gilmour.lan> Message-ID: <20201104111710.GB287014@aptenodytes> Hi, On Mon 02 Nov 20, 10:21, Maxime Ripard wrote: > On Fri, Oct 30, 2020 at 07:45:18PM -0300, Helen Koike wrote: > > On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > > > The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > > > found on Allwinner SoCs such as the A31 and V3/V3s. > > > > > > It is a standalone block, connected to the CSI controller on one side > > > and to the MIPI D-PHY block on the other. It has a dedicated address > > > space, interrupt line and clock. > > > > > > Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > > > controller (CSI0) but newer SoCs (such as the V5) may allow switching > > > MIPI CSI-2 controllers between CSI controllers. > > > > > > It is represented as a V4L2 subdev to the CSI controller and takes a > > > MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > > > media controller API. > > > > Maybe this is a bad idea, but I was thinking: > > This driver basically just turn on/off and catch some interrupts for errors, > > and all the rest of v4l2 config you just forward to the next subdevice > > on the pipeline. > > > > So instead of exposing it as a subdevice, I was wondering if modeling > > this driver also through the phy subsystem wouldn't be cleaner, so > > you won't need all the v4l2 subdevice/topology boilerplate code that > > it seems you are not using (unless you have plans to add controls or > > some specific configuration on this node later). > > > > But this would require changes on the sun6i-csi driver. > > > > What do you think? > > Eventually we'll need to filter the virtual channels / datatypes I > guess, so it's definitely valuable to have it in v4l2 Agreed and like I mentionned in the discussion on 00/14 I don't think it would be a cleaner way to expose things. There's also the fact that newer SoCs like the V5 seem to allow connecting any MIPI CSI-2 controller to any CSI controller, so the graph representation is definitely welcome here. Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Wed Nov 4 11:34:58 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Wed, 4 Nov 2020 12:34:58 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201026165407.rrq6ccsexcsub5bm@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <20201026165407.rrq6ccsexcsub5bm@gilmour.lan> Message-ID: <20201104113458.GC287014@aptenodytes> Hi, On Mon 26 Oct 20, 17:54, Maxime Ripard wrote: > On Fri, Oct 23, 2020 at 07:45:40PM +0200, Paul Kocialkowski wrote: > > The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > > found on Allwinner SoCs such as the A31 and V3/V3s. > > > > It is a standalone block, connected to the CSI controller on one side > > and to the MIPI D-PHY block on the other. It has a dedicated address > > space, interrupt line and clock. > > > > Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > > controller (CSI0) but newer SoCs (such as the V5) may allow switching > > MIPI CSI-2 controllers between CSI controllers. > > > > It is represented as a V4L2 subdev to the CSI controller and takes a > > MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > > media controller API. > > > > Signed-off-by: Paul Kocialkowski > > --- > > drivers/media/platform/sunxi/Kconfig | 1 + > > drivers/media/platform/sunxi/Makefile | 1 + > > .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > > .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 ++++++++++++++++++ > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 ++++ > > 6 files changed, 768 insertions(+) > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > > > diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig > > index 7151cc249afa..9684e07454ad 100644 > > --- a/drivers/media/platform/sunxi/Kconfig > > +++ b/drivers/media/platform/sunxi/Kconfig > > @@ -2,3 +2,4 @@ > > > > source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" > > source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" > > +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" > > diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile > > index fc537c9f5ca9..887a7cae8fca 100644 > > --- a/drivers/media/platform/sunxi/Makefile > > +++ b/drivers/media/platform/sunxi/Makefile > > @@ -2,5 +2,6 @@ > > > > obj-y += sun4i-csi/ > > obj-y += sun6i-csi/ > > +obj-y += sun6i-mipi-csi2/ > > obj-y += sun8i-di/ > > obj-y += sun8i-rotate/ > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > new file mode 100644 > > index 000000000000..7033bda483b4 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > @@ -0,0 +1,11 @@ > > +# SPDX-License-Identifier: GPL-2.0-only > > +config VIDEO_SUN6I_MIPI_CSI2 > > + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" > > + depends on VIDEO_V4L2 && COMMON_CLK > > + depends on ARCH_SUNXI || COMPILE_TEST > > + select MEDIA_CONTROLLER > > + select VIDEO_V4L2_SUBDEV_API > > + select REGMAP_MMIO > > + select V4L2_FWNODE > > + help > > + Support for the Allwinner A31 MIPI CSI-2 Controller. > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > new file mode 100644 > > index 000000000000..14e4e03818b5 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > @@ -0,0 +1,4 @@ > > +# SPDX-License-Identifier: GPL-2.0-only > > +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o > > + > > +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > new file mode 100644 > > index 000000000000..ce89c35f5b86 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > @@ -0,0 +1,635 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright 2020 Bootlin > > + * Author: Paul Kocialkowski > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "sun6i_mipi_csi2.h" > > + > > +#define MODULE_NAME "sun6i-mipi-csi2" > > + > > +/* Core */ > > + > > +static irqreturn_t sun6i_mipi_csi2_isr(int irq, void *dev_id) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev = (struct sun6i_mipi_csi2_dev *)dev_id; > > + struct regmap *regmap = cdev->regmap; > > + u32 pending; > > + > > + WARN_ONCE(1, MODULE_NAME > > + ": Unsolicited interrupt, an error likely occurred!\n"); > > + > > + regmap_read(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, &pending); > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, pending); > > + > > + /* > > + * The interrupt can be used to catch transmission errors. > > + * However, we currently lack plumbing for reporting that to the > > + * A31 CSI controller driver. > > + */ > > + > > + return IRQ_HANDLED; > > +} > > Uhh, what is this handler supposed to be doing? The warning will already > be printed by the core if you return IRQ_NONE, and then, apart from > clearing the interrupt status, it doesn't seem to be doing anything? > > Why should we register a handler in the first place then? Okay I realize it was a bad idea. The bottomline was to put a reminder that this is where transmission errors should be caught but it's pretty obvious anyway. Let's get rid of the routine and leave the IRQ alone. > > +static int sun6i_mipi_csi2_s_power(struct v4l2_subdev *subdev, int on) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + int ret; > > + > > + if (!on) { > > + clk_disable_unprepare(cdev->clk_mod); > > + reset_control_assert(cdev->reset); > > + > > + return 0; > > + } > > + > > + ret = clk_prepare_enable(cdev->clk_mod); > > + if (ret) { > > + dev_err(cdev->dev, "failed to enable module clock\n"); > > + return ret; > > + } > > + > > + ret = reset_control_deassert(cdev->reset); > > + if (ret) { > > + dev_err(cdev->dev, "failed to deassert reset\n"); > > + goto error_clk; > > + } > > The user manual says to do the opposite: deassert the reset line and > then enable the clock, but I'm not sure where the bus clock is handled? Oh I had totally missed that! I think I took inspiration from the CSI controller so there might be an issue with it as well. > > + return 0; > > + > > +error_clk: > > + clk_disable_unprepare(cdev->clk_mod); > > + > > + return ret; > > +} > > + > > +static const struct v4l2_subdev_core_ops sun6i_mipi_csi2_subdev_core_ops = { > > + .s_power = sun6i_mipi_csi2_s_power, > > +}; > > + > > +/* Video */ > > + > > +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + struct v4l2_subdev *remote_subdev = video->remote_subdev; > > + struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = > > + &video->endpoint.bus.mipi_csi2; > > + union phy_configure_opts dphy_opts = { 0 }; > > + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; > > + struct regmap *regmap = cdev->regmap; > > + struct v4l2_ctrl *ctrl; > > + unsigned int lanes_count; > > + unsigned int bpp; > > + unsigned long pixel_rate; > > + u8 data_type = 0; > > + u32 version = 0; > > + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ > > + int ret = 0; > > + > > + if (!remote_subdev) > > + return -ENODEV; > > + > > + if (!on) { > > + v4l2_subdev_call(remote_subdev, video, s_stream, 0); > > + > > +disable: > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_EN, 0); > > + > > + phy_power_off(cdev->dphy); > > + > > + return ret; > > + } > > + > > + switch (video->mbus_code) { > > + case MEDIA_BUS_FMT_SBGGR8_1X8: > > + case MEDIA_BUS_FMT_SGBRG8_1X8: > > + case MEDIA_BUS_FMT_SGRBG8_1X8: > > + case MEDIA_BUS_FMT_SRGGB8_1X8: > > + data_type = MIPI_CSI2_DATA_TYPE_RAW8; > > + bpp = 8; > > + break; > > + case MEDIA_BUS_FMT_SBGGR10_1X10: > > + case MEDIA_BUS_FMT_SGBRG10_1X10: > > + case MEDIA_BUS_FMT_SGRBG10_1X10: > > + case MEDIA_BUS_FMT_SRGGB10_1X10: > > + data_type = MIPI_CSI2_DATA_TYPE_RAW10; > > + bpp = 10; > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + /* Sensor pixel rate */ > > + > > + ctrl = v4l2_ctrl_find(remote_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); > > + if (!ctrl) { > > + dev_err(cdev->dev, > > + "%s: no MIPI CSI-2 pixel rate from the sensor\n", > > + __func__); > > + return -ENODEV; > > + } > > + > > + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); > > + if (!pixel_rate) { > > + dev_err(cdev->dev, > > + "%s: zero MIPI CSI-2 pixel rate from the sensor\n", > > + __func__); > > + return -ENODEV; > > + } > > + > > + /* D-PHY configuration */ > > + > > + lanes_count = bus_mipi_csi2->num_data_lanes; > > + phy_mipi_dphy_get_default_config(pixel_rate, bpp, lanes_count, > > + dphy_cfg); > > + > > + > > + /* > > + * Note that our hardware is using DDR, which is not taken in account by > > + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from > > + * the pixel rate, lanes count and bpp. > > + * > > + * The resulting clock rate is basically the symbol rate over the whole > > + * link. The actual clock rate is calculated with division by two since > > + * DDR samples both on rising and falling edges. > > + */ > > + > > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 config:\n"); > > + dev_dbg(cdev->dev, "%ld pixels/s, %u bits/pixel, %lu Hz clock\n", > > + pixel_rate, bpp, dphy_cfg->hs_clk_rate / 2); > > + > > + ret = 0; > > + ret |= phy_reset(cdev->dphy); > > + ret |= phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, > > + PHY_MIPI_DPHY_SUBMODE_RX); > > + ret |= phy_configure(cdev->dphy, &dphy_opts); > > If you have multiple errors here, chances are you'll get a different > error code, and then ... > > > + if (ret) { > > + dev_err(cdev->dev, "failed to setup MIPI D-PHY\n"); > > + return ret; > > + } > > ... return a completely bogus value here. I'd rather check in each step > and return the error code. Right I missed that. Will check each step. > > + ret = phy_power_on(cdev->dphy); > > + if (ret) { > > + dev_err(cdev->dev, "failed to power on MIPI D-PHY\n"); > > + return ret; > > + } > > + > > + /* MIPI CSI-2 controller setup */ > > + > > + /* > > + * The enable flow in the Allwinner BSP is a bit different: the enable > > + * and reset bits are set together before starting the CSI controller. > > + * > > + * In mainline we enable the CSI controller first (due to subdev logic). > > + * One reliable way to make this work is to deassert reset, configure > > + * registers and enable the controller when everything's ready. > > + * > > + * However, reading the version appears necessary for it to work > > + * reliably. Replacing it with a delay doesn't do the trick. > > + */ > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_RESET_N | > > + SUN6I_MIPI_CSI2_CTL_VERSION_EN | > > + SUN6I_MIPI_CSI2_CTL_UNPK_EN); > > + > > + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); > > + > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); > > + > > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 version: %04x\n", version); > > That's really weird. Are you sure it's not due to the fact that the bus > clock would be enabled and not the reset line, or the other way around? That could be, I'll check. > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, > > + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | > > + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); > > It's not really clear what the channel is here? The number of virtual > channels? Something else? That's somewhat described in the controller documentation. Channels refers to physical channels of the controller, which can be used to redirect data matching either a specific data type, a specific virtual channel, or both. There's a somewhat similar concept of channels in the CSI controller too. We're currently only using one... > > + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); ... but it's safer to configure them all to virtual channel numbers so we don't end up with multiple channels matching virtual channel 0. I'll add a comment about that. > > + > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); > > + > > + ret = v4l2_subdev_call(remote_subdev, video, s_stream, 1); > > + if (ret) > > + goto disable; > > + > > + return 0; > > +} > > + > > +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_subdev_video_ops = { > > + .s_stream = sun6i_mipi_csi2_s_stream, > > +}; > > + > > +/* Pad */ > > + > > +static int sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_mbus_code_enum *code_enum) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + code_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_mbus_code, > > + config, code_enum); > > +} > > + > > +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_format *format) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + format->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, get_fmt, config, > > + format); > > +} > > + > > +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_format *format) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + format->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, set_fmt, config, > > + format); > > +} > > + > > +static int sun6i_mipi_csi2_enum_frame_size(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_frame_size_enum *size_enum) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + size_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_size, > > + config, size_enum); > > +} > > + > > +static int sun6i_mipi_csi2_enum_frame_interval(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_frame_interval_enum *interval_enum) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + interval_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_interval, > > + config, interval_enum); > > +} > > You shouldn't forward those calls here, the MC framework is here to > allow to query each component. Just return what ever that bridge > supports. Yes you're probably right, doing this for the pad ops looks like a mistake. > > +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { > > + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, > > + .get_fmt = sun6i_mipi_csi2_get_fmt, > > + .set_fmt = sun6i_mipi_csi2_set_fmt, > > + .enum_frame_size = sun6i_mipi_csi2_enum_frame_size, > > + .enum_frame_interval = sun6i_mipi_csi2_enum_frame_interval, > > +}; > > + > > +/* Subdev */ > > + > > +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { > > + .core = &sun6i_mipi_csi2_subdev_core_ops, > > + .video = &sun6i_mipi_csi2_subdev_video_ops, > > + .pad = &sun6i_mipi_csi2_subdev_pad_ops, > > +}; > > + > > +/* Notifier */ > > + > > +static int sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, > > + struct v4l2_subdev *remote_subdev, > > + struct v4l2_async_subdev *remote_subdev_async) > > +{ > > + struct v4l2_subdev *subdev = notifier->sd; > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + int source_pad; > > + int ret; > > + > > + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, > > + remote_subdev->fwnode, > > + MEDIA_PAD_FL_SOURCE); > > + if (source_pad < 0) > > + return source_pad; > > + > > + ret = media_create_pad_link(&remote_subdev->entity, source_pad, > > + &subdev->entity, 0, > > + MEDIA_LNK_FL_ENABLED | > > + MEDIA_LNK_FL_IMMUTABLE); > > + if (ret) { > > + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", > > + remote_subdev->entity.name, source_pad, > > + subdev->entity.name, 0); > > + return ret; > > + } > > + > > + video->remote_subdev = remote_subdev; > > + video->remote_pad_index = source_pad; > > + > > + return 0; > > +} > > + > > +static const struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { > > + .bound = sun6i_mipi_csi2_notifier_bound, > > +}; > > + > > +/* Media Entity */ > > + > > +static int sun6i_mipi_csi2_link_validate(struct media_link *link) > > +{ > > + struct v4l2_subdev *subdev = > > + container_of(link->sink->entity, struct v4l2_subdev, entity); > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct v4l2_subdev *remote_subdev; > > + struct v4l2_subdev_format format = { 0 }; > > + int ret; > > + > > + if (!is_media_entity_v4l2_subdev(link->source->entity)) > > + return -EINVAL; > > + > > + remote_subdev = media_entity_to_v4l2_subdev(link->source->entity); > > + > > + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; > > + format.pad = link->source->index; > > + > > + ret = v4l2_subdev_call(remote_subdev, pad, get_fmt, NULL, &format); > > + if (ret) > > + return ret; > > + > > + video->mbus_code = format.format.code; > > + > > + return 0; > > +} > > I'm not really sure what you're trying to validate here? The whole purpose is to retreive video->mbus_code from the subdev, like it's done in the sun6i-csi driver. Maybe there is a more appropriate op to do it? > > +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { > > + .link_validate = sun6i_mipi_csi2_link_validate, > > +}; > > + > > +/* Base Driver */ > > + > > +static int sun6i_mipi_csi2_v4l2_setup(struct sun6i_mipi_csi2_dev *cdev) > > +{ > > + struct sun6i_mipi_csi2_video *video = &cdev->video; > > + struct v4l2_subdev *subdev = &video->subdev; > > + struct v4l2_async_notifier *notifier = &video->notifier; > > + struct fwnode_handle *handle; > > + struct v4l2_fwnode_endpoint *endpoint; > > + int ret; > > + > > + /* Subdev */ > > + > > + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); > > + subdev->dev = cdev->dev; > > + strscpy(subdev->name, MODULE_NAME, sizeof(subdev->name)); > > + v4l2_set_subdevdata(subdev, cdev); > > + > > + /* Entity */ > > + > > + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; > > + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; > > + > > + /* Pads */ > > + > > + video->pads[0].flags = MEDIA_PAD_FL_SINK; > > + video->pads[1].flags = MEDIA_PAD_FL_SOURCE; > > + > > + ret = media_entity_pads_init(&subdev->entity, 2, video->pads); > > + if (ret) > > + return ret; > > + > > + /* Endpoint */ > > + > > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(cdev->dev), 0, 0, > > + FWNODE_GRAPH_ENDPOINT_NEXT); > > + if (!handle) > > + goto error_media_entity; > > + > > + endpoint = &video->endpoint; > > + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; > > + > > + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); > > + fwnode_handle_put(handle); > > + if (ret) > > + goto error_media_entity; > > + > > + /* Notifier */ > > + > > + v4l2_async_notifier_init(notifier); > > + > > + ret = v4l2_async_notifier_add_fwnode_remote_subdev(notifier, handle, > > + &video->subdev_async); > > + if (ret) > > + goto error_media_entity; > > + > > + video->notifier.ops = &sun6i_mipi_csi2_notifier_ops; > > + > > + ret = v4l2_async_subdev_notifier_register(subdev, notifier); > > + if (ret < 0) > > + goto error_notifier; > > + > > + /* Subdev */ > > + > > + ret = v4l2_async_register_subdev(subdev); > > + if (ret < 0) > > + goto error_notifier_registered; > > + > > + return 0; > > + > > +error_notifier_registered: > > + v4l2_async_notifier_unregister(notifier); > > +error_notifier: > > + v4l2_async_notifier_cleanup(notifier); > > +error_media_entity: > > + media_entity_cleanup(&subdev->entity); > > + > > + return ret; > > +} > > + > > +static int sun6i_mipi_csi2_v4l2_teardown(struct sun6i_mipi_csi2_dev *cdev) > > +{ > > + struct sun6i_mipi_csi2_video *video = &cdev->video; > > + struct v4l2_subdev *subdev = &video->subdev; > > + struct v4l2_async_notifier *notifier = &video->notifier; > > + > > + v4l2_async_unregister_subdev(subdev); > > + v4l2_async_notifier_unregister(notifier); > > + v4l2_async_notifier_cleanup(notifier); > > + media_entity_cleanup(&subdev->entity); > > + v4l2_device_unregister_subdev(subdev); > > + > > + return 0; > > +} > > + > > +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { > > + .reg_bits = 32, > > + .reg_stride = 4, > > + .val_bits = 32, > > + .max_register = 0x400, > > +}; > > + > > +static int sun6i_mipi_csi2_resource_request(struct sun6i_mipi_csi2_dev *cdev, > > + struct platform_device *pdev) > > +{ > > + struct resource *res; > > + void __iomem *io_base; > > + int irq; > > + int ret; > > + > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + io_base = devm_ioremap_resource(&pdev->dev, res); > > + if (IS_ERR(io_base)) > > + return PTR_ERR(io_base); > > + > > + cdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, > > + &sun6i_mipi_csi2_regmap_config); > > + if (IS_ERR(cdev->regmap)) { > > + dev_err(&pdev->dev, "failed to init register map\n"); > > + return PTR_ERR(cdev->regmap); > > + } > > Yeah, so that won't work. regmap expects to have access to those > registers when you enable that clock, but that won't happen since the > reset line can be disabled. You would be better off using runtime_pm > here. I don't understand what you mean here or what the problem could be. Here we're just initializing regmap and while this is done before the registers are available for I/O, I don't see why it would cause any issue at this point. The exact same thing is done in the CSI driver. > > + > > + cdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); > > + if (IS_ERR(cdev->clk_mod)) { > > + dev_err(&pdev->dev, "failed to acquire csi clock\n"); > > + return PTR_ERR(cdev->clk_mod); > > + } > > + > > + cdev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); > > + if (IS_ERR(cdev->reset)) { > > + dev_err(&pdev->dev, "failed to get reset controller\n"); > > + return PTR_ERR(cdev->reset); > > + } > > What does it need to be shared with? The reset line is shared with the CSI controller and the CSI driver actually already uses get_shared. > > + irq = platform_get_irq(pdev, 0); > > + if (irq < 0) > > + return -ENXIO; > > + > > + ret = devm_request_irq(&pdev->dev, irq, sun6i_mipi_csi2_isr, 0, > > + MODULE_NAME, cdev); > > + if (ret) { > > + dev_err(&pdev->dev, "failed to request MIPI CSI-2 IRQ\n"); > > + return ret; > > + } > > + > > + cdev->dphy = devm_phy_get(&pdev->dev, "dphy"); > > + if (IS_ERR(cdev->dphy)) { > > + dev_err(&pdev->dev, "failed to get the MIPI D-PHY\n"); > > + return PTR_ERR(cdev->dphy); > > + } > > + > > + ret = phy_init(cdev->dphy); > > + if (ret) { > > + dev_err(&pdev->dev, "failed to initialize the MIPI D-PHY\n"); > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > +static int sun6i_mipi_csi2_probe(struct platform_device *pdev) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev; > > + int ret; > > + > > + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); > > + if (!cdev) > > + return -ENOMEM; > > + > > + cdev->dev = &pdev->dev; > > + > > + ret = sun6i_mipi_csi2_resource_request(cdev, pdev); > > + if (ret) > > + return ret; > > + > > + platform_set_drvdata(pdev, cdev); > > + > > + ret = sun6i_mipi_csi2_v4l2_setup(cdev); > > + if (ret) > > + return ret; > > + > > + return 0; > > +} > > + > > +static int sun6i_mipi_csi2_remove(struct platform_device *pdev) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev = platform_get_drvdata(pdev); > > + > > + phy_exit(cdev->dphy); > > + > > + return sun6i_mipi_csi2_v4l2_teardown(cdev); > > +} > > + > > +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { > > + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, > > + { .compatible = "allwinner,sun8i-v3s-mipi-csi2", }, > > If you have a fallback on the a31 compatible, you don't need the v3s one > > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); > > + > > +static struct platform_driver sun6i_mipi_csi2_platform_driver = { > > + .probe = sun6i_mipi_csi2_probe, > > + .remove = sun6i_mipi_csi2_remove, > > + .driver = { > > + .name = MODULE_NAME, > > + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), > > + }, > > +}; > > +module_platform_driver(sun6i_mipi_csi2_platform_driver); > > + > > +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); > > +MODULE_AUTHOR("Paul Kocialkowski "); > > I guess Kevin should be there too? No, Kevin didn't work on supporting the A31 controller so you won't find his name in this driver. Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From hverkuil at xs4all.nl Wed Nov 4 11:39:11 2020 From: hverkuil at xs4all.nl (Hans Verkuil) Date: Wed, 4 Nov 2020 12:39:11 +0100 Subject: [PATCH -next] media: cedrus: fix reference leak in cedrus_start_streaming In-Reply-To: <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> References: <20201102142622.140001-1-zhangqilong3@huawei.com> <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> Message-ID: <2eb14a6d-4680-1527-0985-fd371e3ba2e8@xs4all.nl> On 02/11/2020 15:18, Maxime Ripard wrote: > On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: >> pm_runtime_get_sync will increment pm usage counter even it >> failed. Forgetting to pm_runtime_put_noidle will result in >> reference leak in cedrus_start_streaming. We should fix it. >> >> Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") >> Signed-off-by: Zhang Qilong > > Shouldn't we fix pm_runtime_get_sync instead then? It seems that most of > the callers get this wrong, and that's definitely non-obvious. It's been discussed before, but nobody stepped up to address this issue. In the end I decided to just accept media patches that fix this in the drivers rather than waiting for some mythical future core fix. Nor do I think that you can just 'fix' pm_runtime_get_sync, since then you will get cases where pm_runtime_put is called once too often. Regards, Hans > > Maxime > From dan.carpenter at oracle.com Wed Nov 4 11:40:15 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Wed, 4 Nov 2020 14:40:15 +0300 Subject: [v2] media: atomisp: Fix error handling path In-Reply-To: <85ff17ad-8aa7-a457-6e23-4f5c1c5152f2@web.de> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> <20201104083121.GG18329@kadam> <85ff17ad-8aa7-a457-6e23-4f5c1c5152f2@web.de> Message-ID: <20201104114015.GH18329@kadam> On Wed, Nov 04, 2020 at 11:30:29AM +0100, Markus Elfring wrote: > >>> Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory > >>> allocation") > >> > >> Please delete a line break for this tag. > > > > Markus, the thing is that we all saw the line break and we just thought > > it didn't matter at all... > > Do you disagree to the known documentation then? > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?id=4ef8451b332662d004df269d4cdeb7d9f31419b5#n123 The documentation is correct but no one wants you to constantly be nagging developers about minor stuff... One thing that I do is I start to write an email and then if I realize it's not worth complaining about and I save it to my postponed messages folder. Then I never send it and I forget about it completely. I have currently have 740 messages in my postponed messages folder. :P That's a lot of whining and complaining which I never sent and the world is the more beautiful for it. regards, dan carpenter From christian.gromm at microchip.com Wed Nov 4 12:42:41 2020 From: christian.gromm at microchip.com (Christian Gromm) Date: Wed, 4 Nov 2020 13:42:41 +0100 Subject: [PATCH] drivers: staging: most: use swabXX functions of kernel Message-ID: <1604493761-19144-1-git-send-email-christian.gromm@microchip.com> This patch makes use of the swab16() and swab32() functions available in the kernel instead of using own implementations. Signed-off-by: Christian Gromm --- drivers/staging/most/sound/sound.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c index 8a449ab..3a1a590 100644 --- a/drivers/staging/most/sound/sound.c +++ b/drivers/staging/most/sound/sound.c @@ -72,22 +72,12 @@ static struct list_head adpt_list; SNDRV_PCM_INFO_INTERLEAVED | \ SNDRV_PCM_INFO_BLOCK_TRANSFER) -#define swap16(val) ( \ - (((u16)(val) << 8) & (u16)0xFF00) | \ - (((u16)(val) >> 8) & (u16)0x00FF)) - -#define swap32(val) ( \ - (((u32)(val) << 24) & (u32)0xFF000000) | \ - (((u32)(val) << 8) & (u32)0x00FF0000) | \ - (((u32)(val) >> 8) & (u32)0x0000FF00) | \ - (((u32)(val) >> 24) & (u32)0x000000FF)) - static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) { unsigned int i = 0; while (i < (bytes / 2)) { - dest[i] = swap16(source[i]); + dest[i] = swab16(source[i]); i++; } } @@ -109,7 +99,7 @@ static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) unsigned int i = 0; while (i < bytes / 4) { - dest[i] = swap32(source[i]); + dest[i] = swab32(source[i]); i++; } } -- 2.7.4 From maxime at cerno.tech Wed Nov 4 12:43:06 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Wed, 4 Nov 2020 13:43:06 +0100 Subject: use of dma_direct_set_offset in (allwinner) drivers In-Reply-To: <9623c346-c86c-e3ce-332b-95492576a859@arm.com> References: <20201103095538.GA19136@lst.de> <20201104081411.bnt5kixgunaczbzj@gilmour.lan> <9623c346-c86c-e3ce-332b-95492576a859@arm.com> Message-ID: <20201104124306.65nfvmr3ceggug4z@gilmour.lan> On Wed, Nov 04, 2020 at 10:15:49AM +0000, Robin Murphy wrote: > On 2020-11-04 08:14, Maxime Ripard wrote: > > Hi Christoph, > > > > On Tue, Nov 03, 2020 at 10:55:38AM +0100, Christoph Hellwig wrote: > > > Linux 5.10-rc1 switched from having a single dma offset in struct device > > > to a set of DMA ranges, and introduced a new helper to set them, > > > dma_direct_set_offset. > > > > > > This in fact surfaced that a bunch of drivers that violate our layering > > > and set the offset from drivers, which meant we had to reluctantly > > > export the symbol to set up the DMA range. > > > > > > The drivers are: > > > > > > drivers/gpu/drm/sun4i/sun4i_backend.c > > > > > > This just use dma_direct_set_offset as a fallback. Is there any good > > > reason to not just kill off the fallback? > > > > > > drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c > > > > > > Same as above. > > > > So, the history of this is: > > > > - We initially introduced the support for those two controllers > > assuming that there was a direct mapping between the physical and > > DMA addresses. It turns out it didn't and the DMA accesses were > > going through a secondary, dedicated, bus that didn't have the same > > mapping of the RAM than the CPU. > > > > 4690803b09c6 ("drm/sun4i: backend: Offset layer buffer address by DRAM starting address") > > > > - This dedicated bus is undocumented and barely used in the vendor > > kernel so this was overlooked, and it's fairly hard to get infos on > > it for all the SoCs we support. We added the DT support for it > > though on some SoCs we had enough infos to do so: > > > > c43a4469402f ("dt-bindings: interconnect: Add a dma interconnect name") > > 22f88e311399 ("ARM: dts: sun5i: Add the MBUS controller") > > > > This explains the check on the interconnect property > > > > - However, due to the stable DT rule, we still need to operate without > > regressions on older DTs that wouldn't have that property (and for > > SoCs we haven't figured out). Hence the fallback. > > How about having something in the platform code that keys off the top-level > SoC compatible and uses a bus notifier to create offsets for the relevant > devices if an MBUS description is missing? At least that way the workaround > could be confined to a single dedicated place and look somewhat similar to > other special cases like sta2x11, rather than being duplicated all over the > place. I'll give it a try, thanks for the suggestion :) Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From christian.gromm at microchip.com Wed Nov 4 12:50:42 2020 From: christian.gromm at microchip.com (Christian Gromm) Date: Wed, 4 Nov 2020 13:50:42 +0100 Subject: [PATCH v2] drivers: staging: most: use swabXX functions of kernel Message-ID: <1604494242-3414-1-git-send-email-christian.gromm@microchip.com> This patch makes use of the swab16() and swab32() functions available in the kernel instead of using own implementations. Signed-off-by: Christian Gromm Reported-by: Greg Kroah-Hartman --- v2: added 'Reported-by:' tag drivers/staging/most/sound/sound.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c index 8a449ab..3a1a590 100644 --- a/drivers/staging/most/sound/sound.c +++ b/drivers/staging/most/sound/sound.c @@ -72,22 +72,12 @@ static struct list_head adpt_list; SNDRV_PCM_INFO_INTERLEAVED | \ SNDRV_PCM_INFO_BLOCK_TRANSFER) -#define swap16(val) ( \ - (((u16)(val) << 8) & (u16)0xFF00) | \ - (((u16)(val) >> 8) & (u16)0x00FF)) - -#define swap32(val) ( \ - (((u32)(val) << 24) & (u32)0xFF000000) | \ - (((u32)(val) << 8) & (u32)0x00FF0000) | \ - (((u32)(val) >> 8) & (u32)0x0000FF00) | \ - (((u32)(val) >> 24) & (u32)0x000000FF)) - static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) { unsigned int i = 0; while (i < (bytes / 2)) { - dest[i] = swap16(source[i]); + dest[i] = swab16(source[i]); i++; } } @@ -109,7 +99,7 @@ static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) unsigned int i = 0; while (i < bytes / 4) { - dest[i] = swap32(source[i]); + dest[i] = swab32(source[i]); i++; } } -- 2.7.4 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:40 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:40 +0530 Subject: [PATCH v7 0/7] clk: clk-wizard: clock-wizard: Driver updates Message-ID: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> In the thread [1] Greg suggested that we move the driver to the clk from the staging. Add patches to address the concerns regarding the fractional and set rate support in the TODO. The patch set does the following - Trivial fixes for kernel doc. - Move the driver to the clk folder - Add capability to set rate. - Add fractional support. - Add support for configurable outputs. - Make the output names unique so that multiple instances do not crib. Changes in the v3: Added the cover-letter. Add patches for rate setting and fractional support Add patches for warning. Remove the driver from staging as suggested v4: Reorder the patches. Merge the CLK_IS_BASIC patch. Add the yaml form of binding document v5: Fix a mismerge v6: Fix the yaml warning use poll timedout v7: Binding doc updates Use common divisor function. [1] https://spinics.net/lists/linux-driver-devel/msg117326.html Shubhrajyoti Datta (7): dt-bindings: add documentation of xilinx clocking wizard clk: clock-wizard: Add the clockwizard to clk directory clk: clock-wizard: Fix kernel-doc warning clk: clock-wizard: Add support for dynamic reconfiguration clk: clock-wizard: Add support for fractional support clk: clock-wizard: Remove the hardcoding of the clock outputs clk: clock-wizard: Update the fixed factor divisors .../bindings/clock/xlnx,clocking-wizard.yaml | 65 ++ drivers/clk/Kconfig | 9 + drivers/clk/Makefile | 1 + drivers/clk/clk-xlnx-clock-wizard.c | 689 +++++++++++++++++++++ drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/clocking-wizard/Kconfig | 10 - drivers/staging/clocking-wizard/Makefile | 2 - drivers/staging/clocking-wizard/TODO | 12 - .../clocking-wizard/clk-xlnx-clock-wizard.c | 333 ---------- drivers/staging/clocking-wizard/dt-binding.txt | 30 - 11 files changed, 764 insertions(+), 390 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml create mode 100644 drivers/clk/clk-xlnx-clock-wizard.c delete mode 100644 drivers/staging/clocking-wizard/Kconfig delete mode 100644 drivers/staging/clocking-wizard/Makefile delete mode 100644 drivers/staging/clocking-wizard/TODO delete mode 100644 drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c delete mode 100644 drivers/staging/clocking-wizard/dt-binding.txt -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:42 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:42 +0530 Subject: [PATCH v7 2/7] clk: clock-wizard: Add the clockwizard to clk directory In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-3-git-send-email-shubhrajyoti.datta@xilinx.com> Add clocking wizard driver to clk. And delete the driver from the staging as it is in drivers/clk. Signed-off-by: Shubhrajyoti Datta --- v7: Combined the patch for deletion and add of the driver dropping the ack from Greg for the staging as it is a combined patch. Add vendor prefix to speedgrade drivers/clk/Kconfig | 9 +++++++ drivers/clk/Makefile | 1 + .../clk-xlnx-clock-wizard.c | 6 +++-- drivers/staging/Kconfig | 2 -- drivers/staging/Makefile | 1 - drivers/staging/clocking-wizard/Kconfig | 10 -------- drivers/staging/clocking-wizard/Makefile | 2 -- drivers/staging/clocking-wizard/TODO | 12 --------- drivers/staging/clocking-wizard/dt-binding.txt | 30 ---------------------- 9 files changed, 14 insertions(+), 59 deletions(-) rename drivers/{staging/clocking-wizard => clk}/clk-xlnx-clock-wizard.c (98%) delete mode 100644 drivers/staging/clocking-wizard/Kconfig delete mode 100644 drivers/staging/clocking-wizard/Makefile delete mode 100644 drivers/staging/clocking-wizard/TODO delete mode 100644 drivers/staging/clocking-wizard/dt-binding.txt diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 4026fac..a0e29dd 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -359,6 +359,15 @@ config COMMON_CLK_FIXED_MMIO help Support for Memory Mapped IO Fixed clocks +config COMMON_CLK_XLNX_CLKWZRD + tristate "Xilinx Clocking Wizard" + depends on COMMON_CLK && OF + help + Support for the Xilinx Clocking Wizard IP core clock generator. + Adds support for clocking wizard and compatible. + This driver supports the Xilinx clocking wizard programmable clock + synthesizer. The number of output is configurable in the design. + source "drivers/clk/actions/Kconfig" source "drivers/clk/analogbits/Kconfig" source "drivers/clk/baikal-t1/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf1..1ad6414 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o # please keep this section sorted lexicographically by directory path name obj-y += actions/ diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c similarity index 98% rename from drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c rename to drivers/clk/clk-xlnx-clock-wizard.c index e52a64b..1bab68e 100644 --- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -2,9 +2,11 @@ /* * Xilinx 'Clocking Wizard' driver * - * Copyright (C) 2013 - 2014 Xilinx + * Copyright (C) 2013 - 2020 Xilinx * * S?ren Brinkmann + * Shubhrajyoti Datta + * */ #include @@ -146,7 +148,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) if (IS_ERR(clk_wzrd->base)) return PTR_ERR(clk_wzrd->base); - ret = of_property_read_u32(np, "speed-grade", &clk_wzrd->speed_grade); + ret = of_property_read_u32(np, "xlnx,speed-grade", &clk_wzrd->speed_grade); if (!ret) { if (clk_wzrd->speed_grade < 1 || clk_wzrd->speed_grade > 3) { dev_warn(&pdev->dev, "invalid speed grade '%d'\n", diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e6c831c..bae49c6 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -76,8 +76,6 @@ source "drivers/staging/gs_fpgaboot/Kconfig" source "drivers/staging/unisys/Kconfig" -source "drivers/staging/clocking-wizard/Kconfig" - source "drivers/staging/fbtft/Kconfig" source "drivers/staging/fsl-dpaa2/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index a3b1fd0..f5a3e57 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -28,7 +28,6 @@ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_UNISYSSPAR) += unisys/ -obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/ obj-$(CONFIG_MOST) += most/ diff --git a/drivers/staging/clocking-wizard/Kconfig b/drivers/staging/clocking-wizard/Kconfig deleted file mode 100644 index 69cf514..0000000 --- a/drivers/staging/clocking-wizard/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Xilinx Clocking Wizard Driver -# - -config COMMON_CLK_XLNX_CLKWZRD - tristate "Xilinx Clocking Wizard" - depends on COMMON_CLK && OF && IOMEM - help - Support for the Xilinx Clocking Wizard IP core clock generator. diff --git a/drivers/staging/clocking-wizard/Makefile b/drivers/staging/clocking-wizard/Makefile deleted file mode 100644 index b1f9152..0000000 --- a/drivers/staging/clocking-wizard/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clk-xlnx-clock-wizard.o diff --git a/drivers/staging/clocking-wizard/TODO b/drivers/staging/clocking-wizard/TODO deleted file mode 100644 index ebe99db..0000000 --- a/drivers/staging/clocking-wizard/TODO +++ /dev/null @@ -1,12 +0,0 @@ -TODO: - - support for fractional multiplier - - support for fractional divider (output 0 only) - - support for set_rate() operations (may benefit from Stephen Boyd's - refactoring of the clk primitives: https://lkml.org/lkml/2014/9/5/766) - - review arithmetic - - overflow after multiplication? - - maximize accuracy before divisions - -Patches to: - Greg Kroah-Hartman - S?ren Brinkmann diff --git a/drivers/staging/clocking-wizard/dt-binding.txt b/drivers/staging/clocking-wizard/dt-binding.txt deleted file mode 100644 index efb67ff..0000000 --- a/drivers/staging/clocking-wizard/dt-binding.txt +++ /dev/null @@ -1,30 +0,0 @@ -Binding for Xilinx Clocking Wizard IP Core - -This binding uses the common clock binding[1]. Details about the devices can be -found in the product guide[2]. - -[1] Documentation/devicetree/bindings/clock/clock-bindings.txt -[2] Clocking Wizard Product Guide -https://www.xilinx.com/support/documentation/ip_documentation/clk_wiz/v5_1/pg065-clk-wiz.pdf - -Required properties: - - compatible: Must be 'xlnx,clocking-wizard' - - reg: Base and size of the cores register space - - clocks: Handle to input clock - - clock-names: Tuple containing 'clk_in1' and 's_axi_aclk' - - clock-output-names: Names for the output clocks - -Optional properties: - - speed-grade: Speed grade of the device (valid values are 1..3) - -Example: - clock-generator at 40040000 { - reg = <0x40040000 0x1000>; - compatible = "xlnx,clocking-wizard"; - speed-grade = <1>; - clock-names = "clk_in1", "s_axi_aclk"; - clocks = <&clkc 15>, <&clkc 15>; - clock-output-names = "clk_out0", "clk_out1", "clk_out2", - "clk_out3", "clk_out4", "clk_out5", - "clk_out6", "clk_out7"; - }; -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:41 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:41 +0530 Subject: [PATCH v7 1/7] dt-bindings: add documentation of xilinx clocking wizard In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-2-git-send-email-shubhrajyoti.datta@xilinx.com> Add the devicetree binding for the xilinx clocking wizard. Signed-off-by: Shubhrajyoti Datta --- v6: Fix a yaml warning v7: Add vendor prefix speed-grade .../bindings/clock/xlnx,clocking-wizard.yaml | 65 ++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml new file mode 100644 index 0000000..a19b9bb --- /dev/null +++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/xlnx,clocking-wizard.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx clocking wizard + +maintainers: + - Shubhrajyoti Datta + +description: | + The clocking wizard is a soft ip clocking block of Xilinx versal. It + reads required input clock frequencies from the devicetree and acts as clock + clock output. + +select: false + +properties: + compatible: + - enum: + - xlnx,clocking-wizard + + "#clock-cells": + const: 1 + + clocks: + items: + - description: clock input + - description: axi clock + + clock-names: + items: + - const: clk_in1 + - const: s_axi_aclk + + xlnx,speed-grade: + - $ref: /schemas/types.yaml#/definitions/uint32 + - enum: [1, 2, 3] + description: + Speed grade of the device. + +required: + - compatible + - "#clock-cells" + - clocks + - clock-names + - speed-grade + +additionalProperties: false + +examples: + - | + clock-generator at 40040000 { + #clock-cells = <1>; + reg = <0x40040000 0x1000>; + compatible = "xlnx,clocking-wizard"; + xlnx,speed-grade = <1>; + clock-names = "clk_in1", "s_axi_aclk"; + clocks = <&clkc 15>, <&clkc 15>; + clock-output-names = "clk_out1", "clk_out2", + "clk_out3", "clk_out4", "clk_out5", + "clk_out6", "clk_out7"; + }; +... -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:47 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:47 +0530 Subject: [PATCH v7 7/7] clk: clock-wizard: Update the fixed factor divisors In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-8-git-send-email-shubhrajyoti.datta@xilinx.com> Update the fixed factor clock registration to register the divisors. Signed-off-by: Shubhrajyoti Datta --- drivers/clk/clk-xlnx-clock-wizard.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clk/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c index d403a74..7f09522 100644 --- a/drivers/clk/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -472,8 +472,10 @@ static int clk_wzrd_probe(struct platform_device *pdev) u32 reg, reg_f, mult; unsigned long rate; const char *clk_name; + void __iomem *ctrl_reg; struct clk_wzrd *clk_wzrd; int outputs; + unsigned long flags = 0; struct device_node *np = pdev->dev.of_node; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); @@ -543,16 +545,17 @@ static int clk_wzrd_probe(struct platform_device *pdev) } outputs = of_property_count_strings(np, "clock-output-names"); - /* register div */ - reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_DIVCLK_DIVIDE_MASK) >> WZRD_DIVCLK_DIVIDE_SHIFT; + if (outputs == 1) + flags = CLK_SET_RATE_PARENT; clk_name = kasprintf(GFP_KERNEL, "%s_mul_div", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; goto err_rm_int_clk; } - clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor + ctrl_reg = clk_wzrd->base + WZRD_CLK_CFG_REG(0); + /* register div */ + clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_divider (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED | @@ -577,7 +580,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) if (!i) clk_wzrd->clkout[i] = clk_wzrd_register_divf (&pdev->dev, clkout_name, - clk_name, 0, + clk_name, flags, clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), WZRD_CLKOUT_DIVIDE_SHIFT, WZRD_CLKOUT_DIVIDE_WIDTH, -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:46 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:46 +0530 Subject: [PATCH v7 6/7] clk: clock-wizard: Remove the hardcoding of the clock outputs In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-7-git-send-email-shubhrajyoti.datta@xilinx.com> The number of output clocks are configurable in the hardware. Currently the driver registers the maximum number of outputs. Fix the same by registering only the outputs that are there. Signed-off-by: Shubhrajyoti Datta --- v4: Assign output in this patch drivers/clk/clk-xlnx-clock-wizard.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c index ed3b0ef..d403a74 100644 --- a/drivers/clk/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -473,6 +473,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) unsigned long rate; const char *clk_name; struct clk_wzrd *clk_wzrd; + int outputs; struct device_node *np = pdev->dev.of_node; clk_wzrd = devm_kzalloc(&pdev->dev, sizeof(*clk_wzrd), GFP_KERNEL); @@ -541,6 +542,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } + outputs = of_property_count_strings(np, "clock-output-names"); /* register div */ reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & WZRD_DIVCLK_DIVIDE_MASK) >> WZRD_DIVCLK_DIVIDE_SHIFT; @@ -562,7 +564,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) } /* register div per output */ - for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) { + for (i = outputs - 1; i >= 0 ; i--) { const char *clkout_name; if (of_property_read_string_index(np, "clock-output-names", i, @@ -593,7 +595,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) if (IS_ERR(clk_wzrd->clkout[i])) { int j; - for (j = i + 1; j < WZRD_NUM_OUTPUTS; j++) + for (j = i + 1; j < outputs; j++) clk_unregister(clk_wzrd->clkout[j]); dev_err(&pdev->dev, "unable to register divider clock\n"); -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:45 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:45 +0530 Subject: [PATCH v7 5/7] clk: clock-wizard: Add support for fractional support In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-6-git-send-email-shubhrajyoti.datta@xilinx.com> Currently the set rate granularity is to integral divisors. Add support for the fractional divisors. Only the first output0 is fractional in the hardware. Signed-off-by: Shubhrajyoti Datta --- v7: Remove unnecessary comments use mult_frac use a common divisor function. drivers/clk/clk-xlnx-clock-wizard.c | 219 ++++++++++++++++++++++++++++++++---- 1 file changed, 199 insertions(+), 20 deletions(-) diff --git a/drivers/clk/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c index 5581b24..ed3b0ef 100644 --- a/drivers/clk/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -29,20 +29,25 @@ #define WZRD_CLKFBOUT_MULT_SHIFT 8 #define WZRD_CLKFBOUT_MULT_MASK (0xff << WZRD_CLKFBOUT_MULT_SHIFT) +#define WZRD_CLKFBOUT_FRAC_SHIFT 16 +#define WZRD_CLKFBOUT_FRAC_MASK (0x3ff << WZRD_CLKFBOUT_FRAC_SHIFT) #define WZRD_DIVCLK_DIVIDE_SHIFT 0 #define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_DIVIDE_SHIFT 0 #define WZRD_CLKOUT_DIVIDE_WIDTH 8 #define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) +#define WZRD_CLKOUT_FRAC_SHIFT 8 +#define WZRD_CLKOUT_FRAC_MASK 0x3ff #define WZRD_DR_MAX_INT_DIV_VALUE 255 -#define WZRD_DR_NUM_RETRIES 10000 #define WZRD_DR_STATUS_REG_OFFSET 0x04 #define WZRD_DR_LOCK_BIT_MASK 0x00000001 #define WZRD_DR_INIT_REG_OFFSET 0x25C #define WZRD_DR_DIV_TO_PHASE_OFFSET 4 #define WZRD_DR_BEGIN_DYNA_RECONF 0x03 +#define WZRD_USEC_POLL 10 +#define WZRD_TIMEOUT_POLL 1000 /* Get the mask from width */ #define div_mask(width) ((1 << (width)) - 1) @@ -52,6 +57,7 @@ enum clk_wzrd_int_clks { wzrd_clk_mul, wzrd_clk_mul_div, + wzrd_clk_mul_frac, wzrd_clk_int_max }; @@ -186,7 +192,7 @@ static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, */ div = DIV_ROUND_CLOSEST(*prate, rate); - return (*prate / div); + return *prate / div; } static const struct clk_ops clk_wzrd_clk_divider_ops = { @@ -195,6 +201,117 @@ static const struct clk_ops clk_wzrd_clk_divider_ops = { .recalc_rate = clk_wzrd_recalc_rate, }; +static unsigned long clk_wzrd_recalc_ratef(struct clk_hw *hw, + unsigned long parent_rate) +{ + unsigned int val; + u32 div, frac; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + val = readl(div_addr); + div = val & div_mask(divider->width); + frac = (val >> WZRD_CLKOUT_FRAC_SHIFT) & WZRD_CLKOUT_FRAC_MASK; + + return mult_frac(parent_rate, 1000, (div * 1000) + frac); +} + +static int clk_wzrd_dynamic_reconfig_f(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int err; + u32 value, pre; + unsigned long rate_div, f, clockout0_div; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + rate_div = ((parent_rate * 1000) / rate); + clockout0_div = rate_div / 1000; + + pre = DIV_ROUND_CLOSEST((parent_rate * 1000), rate); + f = (u32)(pre - (clockout0_div * 1000)); + f = f & WZRD_CLKOUT_FRAC_MASK; + f = f << WZRD_CLKOUT_DIVIDE_WIDTH; + + value = (f | (clockout0_div & WZRD_CLKOUT_DIVIDE_MASK)); + + /* Set divisor and clear phase offset */ + writel(value, div_addr); + writel(0x0, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + return err; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_REG_OFFSET); + + /* Check status register */ + return readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, value, + value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +} + +static long clk_wzrd_round_rate_f(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + return rate; +} + +static const struct clk_ops clk_wzrd_clk_divider_ops_f = { + .round_rate = clk_wzrd_round_rate_f, + .set_rate = clk_wzrd_dynamic_reconfig_f, + .recalc_rate = clk_wzrd_recalc_ratef, +}; + +static struct clk *clk_wzrd_register_divf(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + + init.ops = &clk_wzrd_clk_divider_ops_f; + + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + return ERR_PTR(ret); + + return hw->clk; +} + static struct clk *clk_wzrd_register_divider(struct device *dev, const char *name, const char *parent_name, @@ -229,7 +346,6 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, div->hw.init = &init; div->table = table; - /* register the clock */ hw = &div->hw; ret = devm_clk_hw_register(dev, hw); if (ret) @@ -237,7 +353,6 @@ static struct clk *clk_wzrd_register_divider(struct device *dev, return hw->clk; } - static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, void *data) { @@ -267,6 +382,61 @@ static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, } } +static int clk_wzrd_register_dividers(struct platform_device *pdev, + const char *clk_name) +{ + int i, ret; + struct device_node *np = pdev->dev.of_node; + int outputs; + unsigned long flags = 0; + struct clk_wzrd *clk_wzrd = platform_get_drvdata(pdev); + const char *clkout_name; + + outputs = of_property_count_strings(np, "clock-output-names"); + if (outputs == 1) + flags = CLK_SET_RATE_PARENT; + + for (i = outputs - 1; i >= 0 ; i--) { + if (of_property_read_string_index(np, "clock-output-names", i, + &clkout_name)) { + dev_err(&pdev->dev, + "clock output name not specified\n"); + ret = -EINVAL; + return ret; + } + + if (!i) + clk_wzrd->clkout[i] = clk_wzrd_register_divf + (&pdev->dev, clkout_name, + clk_name, flags, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); + else + clk_wzrd->clkout[i] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, + clk_name, 0, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); + + if (IS_ERR(clk_wzrd->clkout[i])) { + int j; + + for (j = i + 1; j < outputs; j++) + clk_unregister(clk_wzrd->clkout[j]); + dev_err(&pdev->dev, + "unable to register divider clock\n"); + ret = PTR_ERR(clk_wzrd->clkout[i]); + return ret; + } + } + return 0; +} static int __maybe_unused clk_wzrd_suspend(struct device *dev) { struct clk_wzrd *clk_wzrd = dev_get_drvdata(dev); @@ -298,8 +468,8 @@ static SIMPLE_DEV_PM_OPS(clk_wzrd_dev_pm_ops, clk_wzrd_suspend, static int clk_wzrd_probe(struct platform_device *pdev) { - int i, ret; - u32 reg; + int ret; + u32 reg, reg_f, mult; unsigned long rate; const char *clk_name; struct clk_wzrd *clk_wzrd; @@ -349,17 +519,13 @@ static int clk_wzrd_probe(struct platform_device *pdev) goto err_disable_clk; } - /* we don't support fractional div/mul yet */ - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_CLKFBOUT_FRAC_EN; - reg |= readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2)) & - WZRD_CLKOUT0_FRAC_EN; - if (reg) - dev_warn(&pdev->dev, "fractional div/mul not supported\n"); + reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)); + reg_f = reg & WZRD_CLKFBOUT_FRAC_MASK; + reg_f = reg_f >> WZRD_CLKFBOUT_FRAC_SHIFT; - /* register multiplier */ - reg = (readl(clk_wzrd->base + WZRD_CLK_CFG_REG(0)) & - WZRD_CLKFBOUT_MULT_MASK) >> WZRD_CLKFBOUT_MULT_SHIFT; + reg = reg & WZRD_CLKFBOUT_MULT_MASK; + reg = reg >> WZRD_CLKFBOUT_MULT_SHIFT; + mult = (reg * 1000) + reg_f; clk_name = kasprintf(GFP_KERNEL, "%s_mul", dev_name(&pdev->dev)); if (!clk_name) { ret = -ENOMEM; @@ -368,8 +534,7 @@ static int clk_wzrd_probe(struct platform_device *pdev) clk_wzrd->clks_internal[wzrd_clk_mul] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clk_in1), - 0, reg, 1); - kfree(clk_name); + 0, mult, 1000); if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul])) { dev_err(&pdev->dev, "unable to register fixed-factor clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul]); @@ -407,8 +572,18 @@ static int clk_wzrd_probe(struct platform_device *pdev) ret = -EINVAL; goto err_rm_int_clks; } - clk_wzrd->clkout[i] = clk_wzrd_register_divider(&pdev->dev, - clkout_name, + if (!i) + clk_wzrd->clkout[i] = clk_wzrd_register_divf + (&pdev->dev, clkout_name, + clk_name, 0, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); + else + clk_wzrd->clkout[i] = clk_wzrd_register_divider + (&pdev->dev, clkout_name, clk_name, 0, clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), WZRD_CLKOUT_DIVIDE_SHIFT, @@ -427,6 +602,10 @@ static int clk_wzrd_probe(struct platform_device *pdev) } } + ret = clk_wzrd_register_dividers(pdev, clk_name); + if (ret) + goto err_rm_int_clks; + kfree(clk_name); clk_wzrd->clk_data.clks = clk_wzrd->clkout; -- 2.1.1 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:44 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:44 +0100 Subject: [PATCH v3 01/24] mmc: sdio: add SDIO IDs for Silabs WF200 chip In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-2-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Add Silabs SDIO ID to sdio_ids.h. Note that the values used by Silabs are uncommon. A driver cannot fully rely on the SDIO PnP. It should also check if the device is declared in the DT. Signed-off-by: J?r?me Pouiller --- include/linux/mmc/sdio_ids.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h index 12036619346c..20a48162f7fc 100644 --- a/include/linux/mmc/sdio_ids.h +++ b/include/linux/mmc/sdio_ids.h @@ -25,6 +25,11 @@ * Vendors and devices. Sort key: vendor first, device next. */ +// Silabs does not use a reliable vendor ID. To avoid conflicts, the driver +// won't probe the device if it is not also declared in the DT. +#define SDIO_VENDOR_ID_SILABS 0x0000 +#define SDIO_DEVICE_ID_SILABS_WF200 0x1000 + #define SDIO_VENDOR_ID_STE 0x0020 #define SDIO_DEVICE_ID_STE_CW1200 0x2280 -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:43 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:43 +0100 Subject: [PATCH v3 00/24] wfx: get out from the staging area Message-ID: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller I think the wfx driver is now mature enough to be accepted in the drivers/net/wireless directory. As requested by Kalle[1], I send one file per patch. At the end, all the patches (or at least the patches 3 to 24) will be squashed (therefore, I didn't bother to write real commit messages). Here is a diagram of the global architecture that may help to understand the code: ,------------------------------------. | mac80211 | `------------------------------------' ,------------+-----------+-----------. | sta | | | | scan | | | | main | | | +------------+ data_tx | | | key | | data_rx | | hif_tx_mib | queue | | | hif_tx | | | | hif_rx | | | | hif_api_* | | | +------------+-----------+-----------+--------. | bh | fwio | +------------------------------------+--------+ | hwio | +---------------------------------------------+ | bus_sdio | | bus_spi | `---------------------------------------------' ,---------------------------------------------. | spi / sdio | `---------------------------------------------' Roughly, I have sent the files from the bottom to the top. Below the differences with the files from drivers/staging/wfx/: v3: - dt-bindings: Rename config-file property (Rob) - dt-bindings: No additional properties are allowed (spi-max-frequency is already listed) (Rob) - dt-bindings: Remove references for mac-address properties (Rob) - Rebase on staging/staging-next v2: - dt-bindings: Improve device description and add link to the datasheet (Rob) - dt-bindings: Add blank lines between each DT property (Rob) - dt-bindings: Explicitly mention mac-address and local-mac-address and add references to ethernet-controller.yaml (Rob) - dt-bindings: "config-file" is not for development/debug (Rob) - dt-bindings: Remove description of "spi-max-frequency" (Rob) - dt-bindings: Use "folded scalar" syntax instead of escaping the colons - bus_sdio.c: A compatible node in the DT is now mandatory to probe the device. Also change documentation of dt-bindings accordingly (Pali, Ulf) - bus_sdio.c: Move SDIO IDs to sdio_ids.h (Pali) - bh.c: Import patch "staging: wfx: fix test on return value of gpiod_get_value()" (Nathan) - data_tx.c: Import patch "staging: wfx: fix use of uninitialized pointer" - sta.c: Import patch "staging: wfx: make a const array static, makes object smaller" (Colin) v1: - Drop the function name in the warning message (Kalle) - Replace goto by return in wfx_send_pdata_pds() (Kalle, Dan) - Improve error label in wfx_send_pdata_pds() (Kalle) [1] https://lore.kernel.org/lkml/87ft6p2n0h.fsf at codeaurora.org/ J?r?me Pouiller (24): mmc: sdio: add SDIO IDs for Silabs WF200 chip dt-bindings: introduce silabs,wfx.yaml wfx: add Makefile/Kconfig wfx: add wfx.h wfx: add main.c/main.h wfx: add bus.h wfx: add bus_spi.c wfx: add bus_sdio.c wfx: add hwio.c/hwio.h wfx: add fwio.c/fwio.h wfx: add bh.c/bh.h wfx: add hif_api_*.h wfx: add hif_tx*.c/hif_tx*.h wfx: add key.c/key.h wfx: add hif_rx.c/hif_rx.h wfx: add data_rx.c/data_rx.h wfx: add queue.c/queue.h wfx: add data_tx.c/data_tx.h wfx: add sta.c/sta.h wfx: add scan.c/scan.h wfx: add debug.c/debug.h wfx: add traces.h wfx: remove from the staging area wfx: get out from the staging area .../bindings/net/wireless/silabs,wfx.yaml | 64 ++++++++++--------- MAINTAINERS | 3 +- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/silabs/Kconfig | 18 ++++++ drivers/net/wireless/silabs/Makefile | 3 + .../wireless/silabs}/wfx/Kconfig | 0 .../wireless/silabs}/wfx/Makefile | 0 .../{staging => net/wireless/silabs}/wfx/bh.c | 0 .../{staging => net/wireless/silabs}/wfx/bh.h | 0 .../wireless/silabs}/wfx/bus.h | 0 .../wireless/silabs}/wfx/bus_sdio.c | 19 ++---- .../wireless/silabs}/wfx/bus_spi.c | 0 .../wireless/silabs}/wfx/data_rx.c | 0 .../wireless/silabs}/wfx/data_rx.h | 0 .../wireless/silabs}/wfx/data_tx.c | 2 +- .../wireless/silabs}/wfx/data_tx.h | 0 .../wireless/silabs}/wfx/debug.c | 0 .../wireless/silabs}/wfx/debug.h | 0 .../wireless/silabs}/wfx/fwio.c | 0 .../wireless/silabs}/wfx/fwio.h | 0 .../wireless/silabs}/wfx/hif_api_cmd.h | 0 .../wireless/silabs}/wfx/hif_api_general.h | 0 .../wireless/silabs}/wfx/hif_api_mib.h | 0 .../wireless/silabs}/wfx/hif_rx.c | 0 .../wireless/silabs}/wfx/hif_rx.h | 0 .../wireless/silabs}/wfx/hif_tx.c | 0 .../wireless/silabs}/wfx/hif_tx.h | 0 .../wireless/silabs}/wfx/hif_tx_mib.c | 0 .../wireless/silabs}/wfx/hif_tx_mib.h | 0 .../wireless/silabs}/wfx/hwio.c | 0 .../wireless/silabs}/wfx/hwio.h | 0 .../wireless/silabs}/wfx/key.c | 0 .../wireless/silabs}/wfx/key.h | 0 .../wireless/silabs}/wfx/main.c | 9 ++- .../wireless/silabs}/wfx/main.h | 0 .../wireless/silabs}/wfx/queue.c | 0 .../wireless/silabs}/wfx/queue.h | 0 .../wireless/silabs}/wfx/scan.c | 0 .../wireless/silabs}/wfx/scan.h | 0 .../wireless/silabs}/wfx/sta.c | 0 .../wireless/silabs}/wfx/sta.h | 0 .../wireless/silabs}/wfx/traces.h | 0 .../wireless/silabs}/wfx/wfx.h | 0 drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/wfx/TODO | 6 -- include/linux/mmc/sdio_ids.h | 5 ++ 48 files changed, 74 insertions(+), 60 deletions(-) rename {drivers/staging/wfx/Documentation => Documentation}/devicetree/bindings/net/wireless/silabs,wfx.yaml (73%) create mode 100644 drivers/net/wireless/silabs/Kconfig create mode 100644 drivers/net/wireless/silabs/Makefile rename drivers/{staging => net/wireless/silabs}/wfx/Kconfig (100%) rename drivers/{staging => net/wireless/silabs}/wfx/Makefile (100%) rename drivers/{staging => net/wireless/silabs}/wfx/bh.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/bh.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/bus.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/bus_sdio.c (91%) rename drivers/{staging => net/wireless/silabs}/wfx/bus_spi.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/data_rx.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.c (99%) rename drivers/{staging => net/wireless/silabs}/wfx/data_tx.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/debug.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/debug.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/fwio.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/fwio.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_cmd.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_general.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_api_mib.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_rx.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hif_tx_mib.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hwio.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/hwio.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/key.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/key.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/main.c (99%) rename drivers/{staging => net/wireless/silabs}/wfx/main.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/queue.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/queue.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/scan.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/scan.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/sta.c (100%) rename drivers/{staging => net/wireless/silabs}/wfx/sta.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/traces.h (100%) rename drivers/{staging => net/wireless/silabs}/wfx/wfx.h (100%) delete mode 100644 drivers/staging/wfx/TODO -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:45 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:45 +0100 Subject: [PATCH v3 02/24] dt-bindings: introduce silabs,wfx.yaml In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-3-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- .../bindings/net/wireless/silabs,wfx.yaml | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml diff --git a/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml new file mode 100644 index 000000000000..c9fc5ff95b58 --- /dev/null +++ b/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2020, Silicon Laboratories, Inc. +%YAML 1.2 +--- + +$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Silicon Labs WFxxx devicetree bindings + +maintainers: + - J?r?me Pouiller + +description: > + Support for the Wifi chip WFxxx from Silicon Labs. Currently, the only device + from the WFxxx series is the WF200 described here: + https://www.silabs.com/documents/public/data-sheets/wf200-datasheet.pdf + + The WF200 can be connected via SPI or via SDIO. + + For SDIO: + + Declaring the WFxxx chip in device tree is mandatory (usually, the VID/PID is + sufficient for the SDIO devices). + + It is recommended to declare a mmc-pwrseq on SDIO host above WFx. Without + it, you may encounter issues during reboot. The mmc-pwrseq should be + compatible with mmc-pwrseq-simple. Please consult + Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more + information. + + For SPI: + + In add of the properties below, please consult + Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI + related properties. + +properties: + compatible: + const: silabs,wf200 + + reg: + description: + When used on SDIO bus, must be set to 1. When used on SPI bus, it is + the chip select address of the device as defined in the SPI devices + bindings. + maxItems: 1 + + spi-max-frequency: true + + interrupts: + description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and + IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When + SPI is used, this property is required. When SDIO is used, the "in-band" + interrupt provided by the SDIO bus is used unless an interrupt is defined + in the Device Tree. + maxItems: 1 + + reset-gpios: + description: (SPI only) Phandle of gpio that will be used to reset chip + during probe. Without this property, you may encounter issues with warm + boot. (For legacy purpose, the gpio in inverted when compatible == + "silabs,wfx-spi") + + For SDIO, the reset gpio should declared using a mmc-pwrseq. + maxItems: 1 + + wakeup-gpios: + description: Phandle of gpio that will be used to wake-up chip. Without this + property, driver will disable most of power saving features. + maxItems: 1 + + silabs,antenna-config-file: + $ref: /schemas/types.yaml#/definitions/string + description: Use an alternative file for antenna configuration (aka + "Platform Data Set" in Silabs jargon). Default is 'wf200.pds'. + + local-mac-address: true + + mac-address: true + +required: + - compatible + - reg + +examples: + - | + #include + #include + + spi0 { + #address-cells = <1>; + #size-cells = <0>; + + wifi at 0 { + compatible = "silabs,wf200"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_irq &wfx_gpios>; + reg = <0>; + interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + spi-max-frequency = <42000000>; + }; + }; + + - | + #include + #include + + wfx_pwrseq: wfx_pwrseq { + compatible = "mmc-pwrseq-simple"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_reset>; + reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; + }; + + mmc0 { + mmc-pwrseq = <&wfx_pwrseq>; + #address-cells = <1>; + #size-cells = <0>; + + wifi at 1 { + compatible = "silabs,wf200"; + pinctrl-names = "default"; + pinctrl-0 = <&wfx_wakeup>; + reg = <1>; + wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; + }; + }; +... -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:46 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:46 +0100 Subject: [PATCH v3 03/24] wfx: add Makefile/Kconfig In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-4-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/Kconfig | 8 ++++++++ drivers/net/wireless/silabs/wfx/Makefile | 25 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/Kconfig create mode 100644 drivers/net/wireless/silabs/wfx/Makefile diff --git a/drivers/net/wireless/silabs/wfx/Kconfig b/drivers/net/wireless/silabs/wfx/Kconfig new file mode 100644 index 000000000000..83ee4d0ca8c6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/Kconfig @@ -0,0 +1,8 @@ +config WFX + tristate "Silicon Labs wireless chips WF200 and further" + depends on MAC80211 + depends on MMC || !MMC # do not allow WFX=y if MMC=m + depends on (SPI || MMC) + help + This is a driver for Silicons Labs WFxxx series (WF200 and further) + chipsets. This chip can be found on SPI or SDIO buses. diff --git a/drivers/net/wireless/silabs/wfx/Makefile b/drivers/net/wireless/silabs/wfx/Makefile new file mode 100644 index 000000000000..0e0cc982ceab --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/Makefile @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0 + +# Necessary for CREATE_TRACE_POINTS +CFLAGS_debug.o = -I$(src) + +wfx-y := \ + bh.o \ + hwio.o \ + fwio.o \ + hif_tx_mib.o \ + hif_tx.o \ + hif_rx.o \ + queue.o \ + data_tx.o \ + data_rx.o \ + scan.o \ + sta.o \ + key.o \ + main.o \ + sta.o \ + debug.o +wfx-$(CONFIG_SPI) += bus_spi.o +wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o + +obj-$(CONFIG_WFX) += wfx.o -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:47 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:47 +0100 Subject: [PATCH v3 04/24] wfx: add wfx.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-5-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/wfx.h | 166 ++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/wfx.h diff --git a/drivers/net/wireless/silabs/wfx/wfx.h b/drivers/net/wireless/silabs/wfx/wfx.h new file mode 100644 index 000000000000..94898680ccde --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/wfx.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common private data for Silicon Labs WFx chips. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2006, Michael Wu + * Copyright 2004-2006 Jean-Baptiste Note , et al. + */ +#ifndef WFX_H +#define WFX_H + +#include +#include +#include +#include +#include + +#include "bh.h" +#include "data_tx.h" +#include "main.h" +#include "queue.h" +#include "hif_tx.h" + +#define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params +#define USEC_PER_TU 1024 + +struct hwbus_ops; + +struct wfx_dev { + struct wfx_platform_data pdata; + struct device *dev; + struct ieee80211_hw *hw; + struct ieee80211_vif *vif[2]; + struct mac_address addresses[2]; + const struct hwbus_ops *hwbus_ops; + void *hwbus_priv; + + u8 keyset; + struct completion firmware_ready; + struct hif_ind_startup hw_caps; + struct wfx_hif hif; + struct delayed_work cooling_timeout_work; + bool poll_irq; + bool chip_frozen; + struct mutex conf_mutex; + + struct wfx_hif_cmd hif_cmd; + struct sk_buff_head tx_pending; + wait_queue_head_t tx_dequeue; + atomic_t tx_lock; + + atomic_t packet_id; + u32 key_map; + + struct hif_rx_stats rx_stats; + struct mutex rx_stats_lock; + struct hif_tx_power_loop_info tx_power_loop_info; + struct mutex tx_power_loop_info_lock; + int force_ps_timeout; +}; + +struct wfx_vif { + struct wfx_dev *wdev; + struct ieee80211_vif *vif; + struct ieee80211_channel *channel; + int id; + + u32 link_id_map; + + bool after_dtim_tx_allowed; + bool join_in_progress; + + struct delayed_work beacon_loss_work; + + struct wfx_queue tx_queue[4]; + struct tx_policy_cache tx_policy_cache; + struct work_struct tx_policy_upload_work; + + struct work_struct update_tim_work; + + unsigned long uapsd_mask; + + /* avoid some operations in parallel with scan */ + struct mutex scan_lock; + struct work_struct scan_work; + struct completion scan_complete; + bool scan_abort; + struct ieee80211_scan_request *scan_req; + + struct completion set_pm_mode_complete; +}; + +static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) +{ + if (vif_id >= ARRAY_SIZE(wdev->vif)) { + dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id); + return NULL; + } + vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif)); + if (!wdev->vif[vif_id]) { + dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", + vif_id); + return NULL; + } + return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv; +} + +static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, + struct wfx_vif *cur) +{ + int i; + int mark = 0; + struct wfx_vif *tmp; + + if (!cur) + mark = 1; + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + tmp = wdev_to_wvif(wdev, i); + if (mark && tmp) + return tmp; + if (tmp == cur) + mark = 1; + } + return NULL; +} + +static inline int wvif_count(struct wfx_dev *wdev) +{ + int i; + int ret = 0; + struct wfx_vif *wvif; + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + wvif = wdev_to_wvif(wdev, i); + if (wvif) + ret++; + } + return ret; +} + +static inline void memreverse(u8 *src, u8 length) +{ + u8 *lo = src; + u8 *hi = src + length - 1; + u8 swap; + + while (lo < hi) { + swap = *lo; + *lo++ = *hi; + *hi-- = swap; + } +} + +static inline int memzcmp(void *src, unsigned int size) +{ + u8 *buf = src; + + if (!size) + return 0; + if (*buf) + return 1; + return memcmp(buf, buf + 1, size - 1); +} + +#endif /* WFX_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:49 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:49 +0100 Subject: [PATCH v3 06/24] wfx: add bus.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-7-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/bus.h | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/bus.h diff --git a/drivers/net/wireless/silabs/wfx/bus.h b/drivers/net/wireless/silabs/wfx/bus.h new file mode 100644 index 000000000000..ca04b3da6204 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bus.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Common bus abstraction layer. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_BUS_H +#define WFX_BUS_H + +#include +#include + +#define WFX_REG_CONFIG 0x0 +#define WFX_REG_CONTROL 0x1 +#define WFX_REG_IN_OUT_QUEUE 0x2 +#define WFX_REG_AHB_DPORT 0x3 +#define WFX_REG_BASE_ADDR 0x4 +#define WFX_REG_SRAM_DPORT 0x5 +#define WFX_REG_SET_GEN_R_W 0x6 +#define WFX_REG_FRAME_OUT 0x7 + +struct hwbus_ops { + int (*copy_from_io)(void *bus_priv, unsigned int addr, + void *dst, size_t count); + int (*copy_to_io)(void *bus_priv, unsigned int addr, + const void *src, size_t count); + int (*irq_subscribe)(void *bus_priv); + int (*irq_unsubscribe)(void *bus_priv); + void (*lock)(void *bus_priv); + void (*unlock)(void *bus_priv); + size_t (*align_size)(void *bus_priv, size_t size); +}; + +extern struct sdio_driver wfx_sdio_driver; +extern struct spi_driver wfx_spi_driver; + +#endif -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:50 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:50 +0100 Subject: [PATCH v3 07/24] wfx: add bus_spi.c In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-8-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/bus_spi.c | 271 ++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/bus_spi.c diff --git a/drivers/net/wireless/silabs/wfx/bus_spi.c b/drivers/net/wireless/silabs/wfx/bus_spi.c new file mode 100644 index 000000000000..a99125d1a30d --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bus_spi.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SPI interface. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2011, Sagrad Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "wfx.h" +#include "hwio.h" +#include "main.h" +#include "bh.h" + +#define SET_WRITE 0x7FFF /* usage: and operation */ +#define SET_READ 0x8000 /* usage: or operation */ + +#define WFX_RESET_INVERTED 1 + +static const struct wfx_platform_data wfx_spi_pdata = { + .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", + .use_rising_clk = true, +}; + +struct wfx_spi_priv { + struct spi_device *func; + struct wfx_dev *core; + struct gpio_desc *gpio_reset; + bool need_swab; +}; + +/* + * WFx chip read data 16bits at time and place them directly into (little + * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while + * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0") + * + * A little endian host with bits_per_word == 16 should do the right job + * natively. The code below to support big endian host and commonly used SPI + * 8bits. + */ +static int wfx_spi_copy_from_io(void *priv, unsigned int addr, + void *dst, size_t count) +{ + struct wfx_spi_priv *bus = priv; + u16 regaddr = (addr << 12) | (count / 2) | SET_READ; + struct spi_message m; + struct spi_transfer t_addr = { + .tx_buf = ®addr, + .len = sizeof(regaddr), + }; + struct spi_transfer t_msg = { + .rx_buf = dst, + .len = count, + }; + u16 *dst16 = dst; + int ret, i; + + WARN(count % 2, "buffer size must be a multiple of 2"); + + cpu_to_le16s(®addr); + if (bus->need_swab) + swab16s(®addr); + + spi_message_init(&m); + spi_message_add_tail(&t_addr, &m); + spi_message_add_tail(&t_msg, &m); + ret = spi_sync(bus->func, &m); + + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&dst16[i]); + return ret; +} + +static int wfx_spi_copy_to_io(void *priv, unsigned int addr, + const void *src, size_t count) +{ + struct wfx_spi_priv *bus = priv; + u16 regaddr = (addr << 12) | (count / 2); + // FIXME: use a bounce buffer + u16 *src16 = (void *)src; + int ret, i; + struct spi_message m; + struct spi_transfer t_addr = { + .tx_buf = ®addr, + .len = sizeof(regaddr), + }; + struct spi_transfer t_msg = { + .tx_buf = src, + .len = count, + }; + + WARN(count % 2, "buffer size must be a multiple of 2"); + WARN(regaddr & SET_READ, "bad addr or size overflow"); + + cpu_to_le16s(®addr); + + // Register address and CONFIG content always use 16bit big endian + // ("BADC" order) + if (bus->need_swab) + swab16s(®addr); + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&src16[i]); + + spi_message_init(&m); + spi_message_add_tail(&t_addr, &m); + spi_message_add_tail(&t_msg, &m); + ret = spi_sync(bus->func, &m); + + if (bus->need_swab && addr == WFX_REG_CONFIG) + for (i = 0; i < count / 2; i++) + swab16s(&src16[i]); + return ret; +} + +static void wfx_spi_lock(void *priv) +{ +} + +static void wfx_spi_unlock(void *priv) +{ +} + +static irqreturn_t wfx_spi_irq_handler(int irq, void *priv) +{ + struct wfx_spi_priv *bus = priv; + + wfx_bh_request_rx(bus->core); + return IRQ_HANDLED; +} + +static int wfx_spi_irq_subscribe(void *priv) +{ + struct wfx_spi_priv *bus = priv; + u32 flags; + + flags = irq_get_trigger_type(bus->func->irq); + if (!flags) + flags = IRQF_TRIGGER_HIGH; + flags |= IRQF_ONESHOT; + return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL, + wfx_spi_irq_handler, IRQF_ONESHOT, + "wfx", bus); +} + +static int wfx_spi_irq_unsubscribe(void *priv) +{ + struct wfx_spi_priv *bus = priv; + + devm_free_irq(&bus->func->dev, bus->func->irq, bus); + return 0; +} + +static size_t wfx_spi_align_size(void *priv, size_t size) +{ + // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned + return ALIGN(size, 4); +} + +static const struct hwbus_ops wfx_spi_hwbus_ops = { + .copy_from_io = wfx_spi_copy_from_io, + .copy_to_io = wfx_spi_copy_to_io, + .irq_subscribe = wfx_spi_irq_subscribe, + .irq_unsubscribe = wfx_spi_irq_unsubscribe, + .lock = wfx_spi_lock, + .unlock = wfx_spi_unlock, + .align_size = wfx_spi_align_size, +}; + +static int wfx_spi_probe(struct spi_device *func) +{ + struct wfx_spi_priv *bus; + int ret; + + if (!func->bits_per_word) + func->bits_per_word = 16; + ret = spi_setup(func); + if (ret) + return ret; + // Trace below is also displayed by spi_setup() if compiled with DEBUG + dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n", + func->chip_select, func->mode, func->bits_per_word, + func->max_speed_hz); + if (func->bits_per_word != 16 && func->bits_per_word != 8) + dev_warn(&func->dev, "unusual bits/word value: %d\n", + func->bits_per_word); + if (func->max_speed_hz > 50000000) + dev_warn(&func->dev, "%dHz is a very high speed\n", + func->max_speed_hz); + + bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + bus->func = func; + if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) + bus->need_swab = true; + spi_set_drvdata(func, bus); + + bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(bus->gpio_reset)) + return PTR_ERR(bus->gpio_reset); + if (!bus->gpio_reset) { + dev_warn(&func->dev, + "gpio reset is not defined, trying to load firmware anyway\n"); + } else { + gpiod_set_consumer_name(bus->gpio_reset, "wfx reset"); + if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED) + gpiod_toggle_active_low(bus->gpio_reset); + gpiod_set_value_cansleep(bus->gpio_reset, 1); + usleep_range(100, 150); + gpiod_set_value_cansleep(bus->gpio_reset, 0); + usleep_range(2000, 2500); + } + + bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata, + &wfx_spi_hwbus_ops, bus); + if (!bus->core) + return -EIO; + + return wfx_probe(bus->core); +} + +static int wfx_spi_remove(struct spi_device *func) +{ + struct wfx_spi_priv *bus = spi_get_drvdata(func); + + wfx_release(bus->core); + return 0; +} + +/* + * For dynamic driver binding, kernel does not use OF to match driver. It only + * use modalias and modalias is a copy of 'compatible' DT node with vendor + * stripped. + */ +static const struct spi_device_id wfx_spi_id[] = { + { "wfx-spi", WFX_RESET_INVERTED }, + { "wf200", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, wfx_spi_id); + +#ifdef CONFIG_OF +static const struct of_device_id wfx_spi_of_match[] = { + { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED }, + { .compatible = "silabs,wf200" }, + { }, +}; +MODULE_DEVICE_TABLE(of, wfx_spi_of_match); +#endif + +struct spi_driver wfx_spi_driver = { + .driver = { + .name = "wfx-spi", + .of_match_table = of_match_ptr(wfx_spi_of_match), + }, + .id_table = wfx_spi_id, + .probe = wfx_spi_probe, + .remove = wfx_spi_remove, +}; -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:51 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:51 +0100 Subject: [PATCH v3 08/24] wfx: add bus_sdio.c In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-9-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/bus_sdio.c | 258 +++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/bus_sdio.c diff --git a/drivers/net/wireless/silabs/wfx/bus_sdio.c b/drivers/net/wireless/silabs/wfx/bus_sdio.c new file mode 100644 index 000000000000..949119d4920c --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bus_sdio.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * SDIO interface. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include +#include +#include +#include +#include + +#include "bus.h" +#include "wfx.h" +#include "hwio.h" +#include "main.h" +#include "bh.h" + +static const struct wfx_platform_data wfx_sdio_pdata = { + .file_fw = "wfm_wf200", + .file_pds = "wf200.pds", +}; + +struct wfx_sdio_priv { + struct sdio_func *func; + struct wfx_dev *core; + u8 buf_id_tx; + u8 buf_id_rx; + int of_irq; +}; + +static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, + void *dst, size_t count) +{ + struct wfx_sdio_priv *bus = priv; + unsigned int sdio_addr = reg_id << 2; + int ret; + + WARN(reg_id > 7, "chip only has 7 registers"); + WARN(((uintptr_t)dst) & 3, "unaligned buffer size"); + WARN(count & 3, "unaligned buffer address"); + + /* Use queue mode buffers */ + if (reg_id == WFX_REG_IN_OUT_QUEUE) + sdio_addr |= (bus->buf_id_rx + 1) << 7; + ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count); + if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) + bus->buf_id_rx = (bus->buf_id_rx + 1) % 4; + + return ret; +} + +static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, + const void *src, size_t count) +{ + struct wfx_sdio_priv *bus = priv; + unsigned int sdio_addr = reg_id << 2; + int ret; + + WARN(reg_id > 7, "chip only has 7 registers"); + WARN(((uintptr_t)src) & 3, "unaligned buffer size"); + WARN(count & 3, "unaligned buffer address"); + + /* Use queue mode buffers */ + if (reg_id == WFX_REG_IN_OUT_QUEUE) + sdio_addr |= bus->buf_id_tx << 7; + // FIXME: discards 'const' qualifier for src + ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count); + if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) + bus->buf_id_tx = (bus->buf_id_tx + 1) % 32; + + return ret; +} + +static void wfx_sdio_lock(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + sdio_claim_host(bus->func); +} + +static void wfx_sdio_unlock(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + sdio_release_host(bus->func); +} + +static void wfx_sdio_irq_handler(struct sdio_func *func) +{ + struct wfx_sdio_priv *bus = sdio_get_drvdata(func); + + wfx_bh_request_rx(bus->core); +} + +static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) +{ + struct wfx_sdio_priv *bus = priv; + + sdio_claim_host(bus->func); + wfx_bh_request_rx(bus->core); + sdio_release_host(bus->func); + return IRQ_HANDLED; +} + +static int wfx_sdio_irq_subscribe(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + u32 flags; + int ret; + u8 cccr; + + if (!bus->of_irq) { + sdio_claim_host(bus->func); + ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); + sdio_release_host(bus->func); + return ret; + } + + sdio_claim_host(bus->func); + cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL); + cccr |= BIT(0); + cccr |= BIT(bus->func->num); + sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL); + sdio_release_host(bus->func); + flags = irq_get_trigger_type(bus->of_irq); + if (!flags) + flags = IRQF_TRIGGER_HIGH; + flags |= IRQF_ONESHOT; + return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL, + wfx_sdio_irq_handler_ext, flags, + "wfx", bus); +} + +static int wfx_sdio_irq_unsubscribe(void *priv) +{ + struct wfx_sdio_priv *bus = priv; + int ret; + + if (bus->of_irq) + devm_free_irq(&bus->func->dev, bus->of_irq, bus); + sdio_claim_host(bus->func); + ret = sdio_release_irq(bus->func); + sdio_release_host(bus->func); + return ret; +} + +static size_t wfx_sdio_align_size(void *priv, size_t size) +{ + struct wfx_sdio_priv *bus = priv; + + return sdio_align_size(bus->func, size); +} + +static const struct hwbus_ops wfx_sdio_hwbus_ops = { + .copy_from_io = wfx_sdio_copy_from_io, + .copy_to_io = wfx_sdio_copy_to_io, + .irq_subscribe = wfx_sdio_irq_subscribe, + .irq_unsubscribe = wfx_sdio_irq_unsubscribe, + .lock = wfx_sdio_lock, + .unlock = wfx_sdio_unlock, + .align_size = wfx_sdio_align_size, +}; + +static const struct of_device_id wfx_sdio_of_match[] = { + { .compatible = "silabs,wfx-sdio" }, + { .compatible = "silabs,wf200" }, + { }, +}; +MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); + +static int wfx_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct device_node *np = func->dev.of_node; + struct wfx_sdio_priv *bus; + int ret; + + if (func->num != 1) { + dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", + func->num); + return -ENODEV; + } + + bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); + if (!bus) + return -ENOMEM; + + if (!np || !of_match_node(wfx_sdio_of_match, np)) { + dev_warn(&func->dev, "no compatible device found in DT\n"); + return -ENODEV; + } + + bus->func = func; + bus->of_irq = irq_of_parse_and_map(np, 0); + sdio_set_drvdata(func, bus); + func->card->quirks |= MMC_QUIRK_LENIENT_FN0 | + MMC_QUIRK_BLKSZ_FOR_BYTE_MODE | + MMC_QUIRK_BROKEN_BYTE_MODE_512; + + sdio_claim_host(func); + ret = sdio_enable_func(func); + // Block of 64 bytes is more efficient than 512B for frame sizes < 4k + sdio_set_block_size(func, 64); + sdio_release_host(func); + if (ret) + goto err0; + + bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata, + &wfx_sdio_hwbus_ops, bus); + if (!bus->core) { + ret = -EIO; + goto err1; + } + + ret = wfx_probe(bus->core); + if (ret) + goto err1; + + return 0; + +err1: + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); +err0: + return ret; +} + +static void wfx_sdio_remove(struct sdio_func *func) +{ + struct wfx_sdio_priv *bus = sdio_get_drvdata(func); + + wfx_release(bus->core); + sdio_claim_host(func); + sdio_disable_func(func); + sdio_release_host(func); +} + +static const struct sdio_device_id wfx_sdio_ids[] = { + { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) }, + { }, +}; +MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); + +struct sdio_driver wfx_sdio_driver = { + .name = "wfx-sdio", + .id_table = wfx_sdio_ids, + .probe = wfx_sdio_probe, + .remove = wfx_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .of_match_table = wfx_sdio_of_match, + } +}; -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:48 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:48 +0100 Subject: [PATCH v3 05/24] wfx: add main.c/main.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-6-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/main.c | 489 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/main.h | 44 +++ 2 files changed, 533 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/main.c create mode 100644 drivers/net/wireless/silabs/wfx/main.h diff --git a/drivers/net/wireless/silabs/wfx/main.c b/drivers/net/wireless/silabs/wfx/main.c new file mode 100644 index 000000000000..1b490b0098a9 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/main.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Device probe and register. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2008, Johannes Berg + * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). + * Copyright (c) 2007-2009, Christian Lamparter + * Copyright (c) 2006, Michael Wu + * Copyright (c) 2004-2006 Jean-Baptiste Note , et al. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "main.h" +#include "wfx.h" +#include "fwio.h" +#include "hwio.h" +#include "bus.h" +#include "bh.h" +#include "sta.h" +#include "key.h" +#include "scan.h" +#include "debug.h" +#include "data_tx.h" +#include "hif_tx_mib.h" +#include "hif_api_cmd.h" + +#define WFX_PDS_MAX_SIZE 1500 + +MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx"); +MODULE_AUTHOR("J?r?me Pouiller "); +MODULE_LICENSE("GPL"); + +#define RATETAB_ENT(_rate, _rateid, _flags) { \ + .bitrate = (_rate), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ +} + +static struct ieee80211_rate wfx_rates[] = { + RATETAB_ENT(10, 0, 0), + RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(60, 6, 0), + RATETAB_ENT(90, 7, 0), + RATETAB_ENT(120, 8, 0), + RATETAB_ENT(180, 9, 0), + RATETAB_ENT(240, 10, 0), + RATETAB_ENT(360, 11, 0), + RATETAB_ENT(480, 12, 0), + RATETAB_ENT(540, 13, 0), +}; + +#define CHAN2G(_channel, _freq, _flags) { \ + .band = NL80211_BAND_2GHZ, \ + .center_freq = (_freq), \ + .hw_value = (_channel), \ + .flags = (_flags), \ + .max_antenna_gain = 0, \ + .max_power = 30, \ +} + +static struct ieee80211_channel wfx_2ghz_chantable[] = { + CHAN2G(1, 2412, 0), + CHAN2G(2, 2417, 0), + CHAN2G(3, 2422, 0), + CHAN2G(4, 2427, 0), + CHAN2G(5, 2432, 0), + CHAN2G(6, 2437, 0), + CHAN2G(7, 2442, 0), + CHAN2G(8, 2447, 0), + CHAN2G(9, 2452, 0), + CHAN2G(10, 2457, 0), + CHAN2G(11, 2462, 0), + CHAN2G(12, 2467, 0), + CHAN2G(13, 2472, 0), + CHAN2G(14, 2484, 0), +}; + +static const struct ieee80211_supported_band wfx_band_2ghz = { + .channels = wfx_2ghz_chantable, + .n_channels = ARRAY_SIZE(wfx_2ghz_chantable), + .bitrates = wfx_rates, + .n_bitrates = ARRAY_SIZE(wfx_rates), + .ht_cap = { + // Receive caps + .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | + IEEE80211_HT_CAP_MAX_AMSDU | + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), + .ht_supported = 1, + .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, + .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, + .mcs = { + .rx_mask = { 0xFF }, // MCS0 to MCS7 + .rx_highest = cpu_to_le16(72), + .tx_params = IEEE80211_HT_MCS_TX_DEFINED, + }, + }, +}; + +static const struct ieee80211_iface_limit wdev_iface_limits[] = { + { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, + { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, +}; + +static const struct ieee80211_iface_combination wfx_iface_combinations[] = { + { + .num_different_channels = 2, + .max_interfaces = 2, + .limits = wdev_iface_limits, + .n_limits = ARRAY_SIZE(wdev_iface_limits), + } +}; + +static const struct ieee80211_ops wfx_ops = { + .start = wfx_start, + .stop = wfx_stop, + .add_interface = wfx_add_interface, + .remove_interface = wfx_remove_interface, + .config = wfx_config, + .tx = wfx_tx, + .join_ibss = wfx_join_ibss, + .leave_ibss = wfx_leave_ibss, + .conf_tx = wfx_conf_tx, + .hw_scan = wfx_hw_scan, + .cancel_hw_scan = wfx_cancel_hw_scan, + .start_ap = wfx_start_ap, + .stop_ap = wfx_stop_ap, + .sta_add = wfx_sta_add, + .sta_remove = wfx_sta_remove, + .set_tim = wfx_set_tim, + .set_key = wfx_set_key, + .set_rts_threshold = wfx_set_rts_threshold, + .set_default_unicast_key = wfx_set_default_unicast_key, + .bss_info_changed = wfx_bss_info_changed, + .configure_filter = wfx_configure_filter, + .ampdu_action = wfx_ampdu_action, + .flush = wfx_flush, + .add_chanctx = wfx_add_chanctx, + .remove_chanctx = wfx_remove_chanctx, + .change_chanctx = wfx_change_chanctx, + .assign_vif_chanctx = wfx_assign_vif_chanctx, + .unassign_vif_chanctx = wfx_unassign_vif_chanctx, +}; + +bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor) +{ + if (wdev->hw_caps.api_version_major < major) + return true; + if (wdev->hw_caps.api_version_major > major) + return false; + if (wdev->hw_caps.api_version_minor < minor) + return true; + return false; +} + +/* NOTE: wfx_send_pds() destroy buf */ +int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) +{ + int ret; + int start, brace_level, i; + + start = 0; + brace_level = 0; + if (buf[0] != '{') { + dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); + return -EINVAL; + } + for (i = 1; i < len - 1; i++) { + if (buf[i] == '{') + brace_level++; + if (buf[i] == '}') + brace_level--; + if (buf[i] == '}' && !brace_level) { + i++; + if (i - start + 1 > WFX_PDS_MAX_SIZE) + return -EFBIG; + buf[start] = '{'; + buf[i] = 0; + dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start); + buf[i] = '}'; + ret = hif_configuration(wdev, buf + start, + i - start + 1); + if (ret > 0) { + dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", + start, i); + return -EINVAL; + } + if (ret == -ETIMEDOUT) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", + start, i); + return ret; + } + if (ret) { + dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", + start, i); + return -EIO; + } + buf[i] = ','; + start = i; + } + } + return 0; +} + +static int wfx_send_pdata_pds(struct wfx_dev *wdev) +{ + int ret = 0; + const struct firmware *pds; + u8 *tmp_buf; + + ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); + if (ret) { + dev_err(wdev->dev, "can't load PDS file %s\n", + wdev->pdata.file_pds); + return ret; + } + tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); + if (!tmp_buf) { + ret = -ENOMEM; + goto release_fw; + } + ret = wfx_send_pds(wdev, tmp_buf, pds->size); + kfree(tmp_buf); +release_fw: + release_firmware(pds); + return ret; +} + +static void wfx_free_common(void *data) +{ + struct wfx_dev *wdev = data; + + mutex_destroy(&wdev->tx_power_loop_info_lock); + mutex_destroy(&wdev->rx_stats_lock); + mutex_destroy(&wdev->conf_mutex); + ieee80211_free_hw(wdev->hw); +} + +struct wfx_dev *wfx_init_common(struct device *dev, + const struct wfx_platform_data *pdata, + const struct hwbus_ops *hwbus_ops, + void *hwbus_priv) +{ + struct ieee80211_hw *hw; + struct wfx_dev *wdev; + + hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), &wfx_ops); + if (!hw) + return NULL; + + SET_IEEE80211_DEV(hw, dev); + + ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); + ieee80211_hw_set(hw, AMPDU_AGGREGATION); + ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); + ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); + ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, SUPPORTS_PS); + ieee80211_hw_set(hw, MFP_CAPABLE); + + hw->vif_data_size = sizeof(struct wfx_vif); + hw->sta_data_size = sizeof(struct wfx_sta_priv); + hw->queues = 4; + hw->max_rates = 8; + hw->max_rate_tries = 8; + hw->extra_tx_headroom = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + + 4 /* alignment */ + 8 /* TKIP IV */; + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; + hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; + hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; + hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX; + hw->wiphy->max_scan_ssids = 2; + hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; + hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); + hw->wiphy->iface_combinations = wfx_iface_combinations; + hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL); + // FIXME: also copy wfx_rates and wfx_2ghz_chantable + memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, + sizeof(wfx_band_2ghz)); + + wdev = hw->priv; + wdev->hw = hw; + wdev->dev = dev; + wdev->hwbus_ops = hwbus_ops; + wdev->hwbus_priv = hwbus_priv; + memcpy(&wdev->pdata, pdata, sizeof(*pdata)); + of_property_read_string(dev->of_node, "silabs,antenna-config-file", + &wdev->pdata.file_pds); + wdev->pdata.gpio_wakeup = devm_gpiod_get_optional(dev, "wakeup", + GPIOD_OUT_LOW); + if (IS_ERR(wdev->pdata.gpio_wakeup)) + return NULL; + if (wdev->pdata.gpio_wakeup) + gpiod_set_consumer_name(wdev->pdata.gpio_wakeup, "wfx wakeup"); + + mutex_init(&wdev->conf_mutex); + mutex_init(&wdev->rx_stats_lock); + mutex_init(&wdev->tx_power_loop_info_lock); + init_completion(&wdev->firmware_ready); + INIT_DELAYED_WORK(&wdev->cooling_timeout_work, + wfx_cooling_timeout_work); + skb_queue_head_init(&wdev->tx_pending); + init_waitqueue_head(&wdev->tx_dequeue); + wfx_init_hif_cmd(&wdev->hif_cmd); + wdev->force_ps_timeout = -1; + + if (devm_add_action_or_reset(dev, wfx_free_common, wdev)) + return NULL; + + return wdev; +} + +int wfx_probe(struct wfx_dev *wdev) +{ + int i; + int err; + const void *macaddr; + struct gpio_desc *gpio_saved; + + // During first part of boot, gpio_wakeup cannot yet been used. So + // prevent bh() to touch it. + gpio_saved = wdev->pdata.gpio_wakeup; + wdev->pdata.gpio_wakeup = NULL; + wdev->poll_irq = true; + + wfx_bh_register(wdev); + + err = wfx_init_device(wdev); + if (err) + goto err0; + + wfx_bh_poll_irq(wdev); + err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ); + if (err <= 0) { + if (err == 0) { + dev_err(wdev->dev, "timeout while waiting for startup indication\n"); + err = -ETIMEDOUT; + } else if (err == -ERESTARTSYS) { + dev_info(wdev->dev, "probe interrupted by user\n"); + } + goto err0; + } + + // FIXME: fill wiphy::hw_version + dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n", + wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor, + wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, + wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, + wdev->keyset, wdev->hw_caps.link_mode); + snprintf(wdev->hw->wiphy->fw_version, + sizeof(wdev->hw->wiphy->fw_version), + "%d.%d.%d", + wdev->hw_caps.firmware_major, + wdev->hw_caps.firmware_minor, + wdev->hw_caps.firmware_build); + + if (wfx_api_older_than(wdev, 1, 0)) { + dev_err(wdev->dev, + "unsupported firmware API version (expect 1 while firmware returns %d)\n", + wdev->hw_caps.api_version_major); + err = -ENOTSUPP; + goto err0; + } + + if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) { + dev_err(wdev->dev, + "chip require secure_link, but can't negotiate it\n"); + goto err0; + } + + if (wdev->hw_caps.region_sel_mode) { + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR; + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR; + wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED; + } + + dev_dbg(wdev->dev, "sending configuration file %s\n", + wdev->pdata.file_pds); + err = wfx_send_pdata_pds(wdev); + if (err < 0) + goto err0; + + wdev->poll_irq = false; + err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv); + if (err) + goto err0; + + err = hif_use_multi_tx_conf(wdev, true); + if (err) + dev_err(wdev->dev, "misconfigured IRQ?\n"); + + wdev->pdata.gpio_wakeup = gpio_saved; + if (wdev->pdata.gpio_wakeup) { + dev_dbg(wdev->dev, + "enable 'quiescent' power mode with wakeup GPIO and PDS file %s\n", + wdev->pdata.file_pds); + gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); + control_reg_write(wdev, 0); + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT); + } else { + hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); + } + + for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { + eth_zero_addr(wdev->addresses[i].addr); + macaddr = of_get_mac_address(wdev->dev->of_node); + if (!IS_ERR_OR_NULL(macaddr)) { + ether_addr_copy(wdev->addresses[i].addr, macaddr); + wdev->addresses[i].addr[ETH_ALEN - 1] += i; + } else { + ether_addr_copy(wdev->addresses[i].addr, + wdev->hw_caps.mac_addr[i]); + } + if (!is_valid_ether_addr(wdev->addresses[i].addr)) { + dev_warn(wdev->dev, "using random MAC address\n"); + eth_random_addr(wdev->addresses[i].addr); + } + dev_info(wdev->dev, "MAC address %d: %pM\n", i, + wdev->addresses[i].addr); + } + wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses); + wdev->hw->wiphy->addresses = wdev->addresses; + + err = ieee80211_register_hw(wdev->hw); + if (err) + goto err1; + + err = wfx_debug_init(wdev); + if (err) + goto err2; + + return 0; + +err2: + ieee80211_unregister_hw(wdev->hw); +err1: + wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); +err0: + wfx_bh_unregister(wdev); + return err; +} + +void wfx_release(struct wfx_dev *wdev) +{ + ieee80211_unregister_hw(wdev->hw); + hif_shutdown(wdev); + wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); + wfx_bh_unregister(wdev); +} + +static int __init wfx_core_init(void) +{ + int ret = 0; + + if (IS_ENABLED(CONFIG_SPI)) + ret = spi_register_driver(&wfx_spi_driver); + if (IS_ENABLED(CONFIG_MMC) && !ret) + ret = sdio_register_driver(&wfx_sdio_driver); + return ret; +} +module_init(wfx_core_init); + +static void __exit wfx_core_exit(void) +{ + if (IS_ENABLED(CONFIG_MMC)) + sdio_unregister_driver(&wfx_sdio_driver); + if (IS_ENABLED(CONFIG_SPI)) + spi_unregister_driver(&wfx_spi_driver); +} +module_exit(wfx_core_exit); diff --git a/drivers/net/wireless/silabs/wfx/main.h b/drivers/net/wireless/silabs/wfx/main.h new file mode 100644 index 000000000000..a0db322383a3 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/main.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Device probe and register. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (c) 2006, Michael Wu + * Copyright 2004-2006 Jean-Baptiste Note , et al. + */ +#ifndef WFX_MAIN_H +#define WFX_MAIN_H + +#include +#include + +#include "hif_api_general.h" + +struct wfx_dev; +struct hwbus_ops; + +struct wfx_platform_data { + /* Keyset and ".sec" extension will be appended to this string */ + const char *file_fw; + const char *file_pds; + struct gpio_desc *gpio_wakeup; + /* + * if true HIF D_out is sampled on the rising edge of the clock + * (intended to be used in 50Mhz SDIO) + */ + bool use_rising_clk; +}; + +struct wfx_dev *wfx_init_common(struct device *dev, + const struct wfx_platform_data *pdata, + const struct hwbus_ops *hwbus_ops, + void *hwbus_priv); + +int wfx_probe(struct wfx_dev *wdev); +void wfx_release(struct wfx_dev *wdev); + +bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); +int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len); + +#endif -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:52 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:52 +0100 Subject: [PATCH v3 09/24] wfx: add hwio.c/hwio.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-10-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/hwio.c | 352 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/hwio.h | 75 ++++++ 2 files changed, 427 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hwio.c create mode 100644 drivers/net/wireless/silabs/wfx/hwio.h diff --git a/drivers/net/wireless/silabs/wfx/hwio.c b/drivers/net/wireless/silabs/wfx/hwio.c new file mode 100644 index 000000000000..36fbc5b5d64c --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hwio.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Low-level I/O functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include + +#include "hwio.h" +#include "wfx.h" +#include "bus.h" +#include "traces.h" + +/* + * Internal helpers. + * + * About CONFIG_VMAP_STACK: + * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack + * allocated data. Functions below that work with registers (aka functions + * ending with "32") automatically reallocate buffers with kmalloc. However, + * functions that work with arbitrary length buffers let's caller to handle + * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located + * buffer. + */ + +static int read32(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + *val = ~0; // Never return undefined value + if (!tmp) + return -ENOMEM; + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, + sizeof(u32)); + if (ret >= 0) + *val = le32_to_cpu(*tmp); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +static int write32(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, + sizeof(u32)); + kfree(tmp); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, val); + _trace_io_read32(reg, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_locked(struct wfx_dev *wdev, int reg, u32 val) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = write32(wdev, reg, val); + _trace_io_write32(reg, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) +{ + int ret; + u32 val_r, val_w; + + WARN_ON(~mask & val); + val &= mask; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = read32(wdev, reg, &val_r); + _trace_io_read32(reg, val_r); + if (ret < 0) + goto err; + val_w = (val_r & ~mask) | val; + if (val_w != val_r) { + ret = write32(wdev, reg, val_w); + _trace_io_write32(reg, val_w); + } +err: + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, + void *buf, size_t len) +{ + int ret; + int i; + u32 cfg; + u32 prefetch; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + + if (reg == WFX_REG_AHB_DPORT) + prefetch = CFG_PREFETCH_AHB; + else if (reg == WFX_REG_SRAM_DPORT) + prefetch = CFG_PREFETCH_SRAM; + else + return -ENODEV; + + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + goto err; + + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + + ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch); + if (ret < 0) + goto err; + + for (i = 0; i < 20; i++) { + ret = read32(wdev, WFX_REG_CONFIG, &cfg); + if (ret < 0) + goto err; + if (!(cfg & prefetch)) + break; + usleep_range(200, 250); + } + if (i == 20) { + ret = -ETIMEDOUT; + goto err; + } + + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); + +err: + if (ret < 0) + memset(buf, 0xFF, len); // Never return undefined value + return ret; +} + +static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr, + const void *buf, size_t len) +{ + int ret; + + WARN_ON(len >= 0x2000); + WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); + ret = write32(wdev, WFX_REG_BASE_ADDR, addr); + if (ret < 0) + return ret; + + return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); +} + +static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, + void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, buf, len); + _trace_io_ind_read(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, + const void *buf, size_t len) +{ + int ret; + + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, buf, len); + _trace_io_ind_write(reg, addr, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + return ret; +} + +static int indirect_read32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 *val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); + *val = le32_to_cpu(*tmp); + _trace_io_ind_read32(reg, addr, *val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +static int indirect_write32_locked(struct wfx_dev *wdev, int reg, + u32 addr, u32 val) +{ + int ret; + __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); + + if (!tmp) + return -ENOMEM; + *tmp = cpu_to_le32(val); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32)); + _trace_io_ind_write32(reg, addr, val); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + kfree(tmp); + return ret; +} + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) +{ + int ret; + + WARN((long)buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, + WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) +{ + int ret; + + WARN((long)buf & 3, "%s: unaligned buffer", __func__); + wdev->hwbus_ops->lock(wdev->hwbus_priv); + ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, + WFX_REG_IN_OUT_QUEUE, buf, len); + _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); + wdev->hwbus_ops->unlock(wdev->hwbus_priv); + if (ret) + dev_err(wdev->dev, "%s: bus communication error: %d\n", + __func__, ret); + return ret; +} + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) +{ + return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); +} + +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) +{ + return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); +} + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) +{ + return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); +} + +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) +{ + return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); +} + +int config_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONFIG, val); +} + +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); +} + +int control_reg_read(struct wfx_dev *wdev, u32 *val) +{ + return read32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write(struct wfx_dev *wdev, u32 val) +{ + return write32_locked(wdev, WFX_REG_CONTROL, val); +} + +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) +{ + return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); +} + +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) +{ + int ret; + + *val = ~0; // Never return undefined value + ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); + if (ret) + return ret; + ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); + if (ret) + return ret; + *val &= IGPR_VALUE; + return ret; +} + +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) +{ + return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); +} diff --git a/drivers/net/wireless/silabs/wfx/hwio.h b/drivers/net/wireless/silabs/wfx/hwio.h new file mode 100644 index 000000000000..0b8e4f7157df --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hwio.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Low-level API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_HWIO_H +#define WFX_HWIO_H + +#include + +struct wfx_dev; + +int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len); +int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len); + +int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); +int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); + +int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); +int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); + +#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI +#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO +#define CFG_ERR_BUF_UNDERRUN 0x00000002 +#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004 +#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008 +#define CFG_ERR_BUF_OVERRUN 0x00000010 +#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020 +#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040 +#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO +#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI +#define CFG_BYTE_ORDER_MASK 0x00000300 // only writable with SPI +#define CFG_BYTE_ORDER_BADC 0x00000000 +#define CFG_BYTE_ORDER_DCBA 0x00000100 +#define CFG_BYTE_ORDER_ABCD 0x00000200 // SDIO always use this value +#define CFG_DIRECT_ACCESS_MODE 0x00000400 +#define CFG_PREFETCH_AHB 0x00000800 +#define CFG_DISABLE_CPU_CLK 0x00001000 +#define CFG_PREFETCH_SRAM 0x00002000 +#define CFG_CPU_RESET 0x00004000 +#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO +#define CFG_IRQ_ENABLE_DATA 0x00010000 +#define CFG_IRQ_ENABLE_WRDY 0x00020000 +#define CFG_CLK_RISE_EDGE 0x00040000 +#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO +#define CFG_RESERVED 0x00F00000 +#define CFG_DEVICE_ID_MAJOR 0x07000000 +#define CFG_DEVICE_ID_RESERVED 0x78000000 +#define CFG_DEVICE_ID_TYPE 0x80000000 +int config_reg_read(struct wfx_dev *wdev, u32 *val); +int config_reg_write(struct wfx_dev *wdev, u32 val); +int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define CTRL_NEXT_LEN_MASK 0x00000FFF +#define CTRL_WLAN_WAKEUP 0x00001000 +#define CTRL_WLAN_READY 0x00002000 +int control_reg_read(struct wfx_dev *wdev, u32 *val); +int control_reg_write(struct wfx_dev *wdev, u32 val); +int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); + +#define IGPR_RW 0x80000000 +#define IGPR_INDEX 0x7F000000 +#define IGPR_VALUE 0x00FFFFFF +int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val); +int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val); + +#endif /* WFX_HWIO_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:53 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:53 +0100 Subject: [PATCH v3 10/24] wfx: add fwio.c/fwio.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-11-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/fwio.c | 405 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/fwio.h | 15 + 2 files changed, 420 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/fwio.c create mode 100644 drivers/net/wireless/silabs/wfx/fwio.h diff --git a/drivers/net/wireless/silabs/wfx/fwio.c b/drivers/net/wireless/silabs/wfx/fwio.c new file mode 100644 index 000000000000..1b8aec02d169 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/fwio.c @@ -0,0 +1,405 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Firmware loading. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include +#include + +#include "fwio.h" +#include "wfx.h" +#include "hwio.h" + +// Addresses below are in SRAM area +#define WFX_DNLD_FIFO 0x09004000 +#define DNLD_BLOCK_SIZE 0x0400 +#define DNLD_FIFO_SIZE 0x8000 // (32 * DNLD_BLOCK_SIZE) +// Download Control Area (DCA) +#define WFX_DCA_IMAGE_SIZE 0x0900C000 +#define WFX_DCA_PUT 0x0900C004 +#define WFX_DCA_GET 0x0900C008 +#define WFX_DCA_HOST_STATUS 0x0900C00C +#define HOST_READY 0x87654321 +#define HOST_INFO_READ 0xA753BD99 +#define HOST_UPLOAD_PENDING 0xABCDDCBA +#define HOST_UPLOAD_COMPLETE 0xD4C64A99 +#define HOST_OK_TO_JUMP 0x174FC882 +#define WFX_DCA_NCP_STATUS 0x0900C010 +#define NCP_NOT_READY 0x12345678 +#define NCP_READY 0x87654321 +#define NCP_INFO_READY 0xBD53EF99 +#define NCP_DOWNLOAD_PENDING 0xABCDDCBA +#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA +#define NCP_AUTH_OK 0xD4C64A99 +#define NCP_AUTH_FAIL 0x174FC882 +#define NCP_PUB_KEY_RDY 0x7AB41D19 +#define WFX_DCA_FW_SIGNATURE 0x0900C014 +#define FW_SIGNATURE_SIZE 0x40 +#define WFX_DCA_FW_HASH 0x0900C054 +#define FW_HASH_SIZE 0x08 +#define WFX_DCA_FW_VERSION 0x0900C05C +#define FW_VERSION_SIZE 0x04 +#define WFX_DCA_RESERVED 0x0900C060 +#define DCA_RESERVED_SIZE 0x20 +#define WFX_STATUS_INFO 0x0900C080 +#define WFX_BOOTLOADER_LABEL 0x0900C084 +#define BOOTLOADER_LABEL_SIZE 0x3C +#define WFX_PTE_INFO 0x0900C0C0 +#define PTE_INFO_KEYSET_IDX 0x0D +#define PTE_INFO_SIZE 0x10 +#define WFX_ERR_INFO 0x0900C0D0 +#define ERR_INVALID_SEC_TYPE 0x05 +#define ERR_SIG_VERIF_FAILED 0x0F +#define ERR_AES_CTRL_KEY 0x10 +#define ERR_ECC_PUB_KEY 0x11 +#define ERR_MAC_KEY 0x18 + +#define DCA_TIMEOUT 50 // milliseconds +#define WAKEUP_TIMEOUT 200 // milliseconds + +static const char * const fwio_errors[] = { + [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption", + [ERR_SIG_VERIF_FAILED] = "Signature verification failed", + [ERR_AES_CTRL_KEY] = "AES control key not initialized", + [ERR_ECC_PUB_KEY] = "ECC public key not initialized", + [ERR_MAC_KEY] = "MAC key not initialized", +}; + +/* + * request_firmware() allocate data using vmalloc(). It is not compatible with + * underlying hardware that use DMA. Function below detect this case and + * allocate a bounce buffer if necessary. + * + * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to + * detect this problem at runtime (else, kernel silently fail). + * + * NOTE: it may also be possible to use 'pages' from struct firmware and avoid + * bounce buffer + */ +static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, + size_t len) +{ + int ret; + const u8 *tmp; + + if (!virt_addr_valid(buf)) { + tmp = kmemdup(buf, len, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + } else { + tmp = buf; + } + ret = sram_buf_write(wdev, addr, tmp, len); + if (tmp != buf) + kfree(tmp); + return ret; +} + +static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, + const struct firmware **fw, int *file_offset) +{ + int keyset_file; + char filename[256]; + const char *data; + int ret; + + snprintf(filename, sizeof(filename), "%s_%02X.sec", + wdev->pdata.file_fw, keyset_chip); + ret = firmware_request_nowarn(fw, filename, wdev->dev); + if (ret) { + dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n", + filename, wdev->pdata.file_fw); + snprintf(filename, sizeof(filename), "%s.sec", + wdev->pdata.file_fw); + ret = request_firmware(fw, filename, wdev->dev); + if (ret) { + dev_err(wdev->dev, "can't load %s\n", filename); + *fw = NULL; + return ret; + } + } + + data = (*fw)->data; + if (memcmp(data, "KEYSET", 6) != 0) { + // Legacy firmware format + *file_offset = 0; + keyset_file = 0x90; + } else { + *file_offset = 8; + keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]); + if (keyset_file < 0) { + dev_err(wdev->dev, "%s corrupted\n", filename); + release_firmware(*fw); + *fw = NULL; + return -EINVAL; + } + } + if (keyset_file != keyset_chip) { + dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n", + keyset_file, keyset_chip); + release_firmware(*fw); + *fw = NULL; + return -ENODEV; + } + wdev->keyset = keyset_file; + return 0; +} + +static int wait_ncp_status(struct wfx_dev *wdev, u32 status) +{ + ktime_t now, start; + u32 reg; + int ret; + + start = ktime_get(); + for (;;) { + ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, ®); + if (ret < 0) + return -EIO; + now = ktime_get(); + if (reg == status) + break; + if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) + return -ETIMEDOUT; + } + if (ktime_compare(now, start)) + dev_dbg(wdev->dev, "chip answer after %lldus\n", + ktime_us_delta(now, start)); + else + dev_dbg(wdev->dev, "chip answer immediately\n"); + return 0; +} + +static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len) +{ + int ret; + u32 offs, bytes_done = 0; + ktime_t now, start; + + if (len % DNLD_BLOCK_SIZE) { + dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n"); + return -EIO; + } + offs = 0; + while (offs < len) { + start = ktime_get(); + for (;;) { + now = ktime_get(); + if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE) + break; + if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) + return -ETIMEDOUT; + ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done); + if (ret < 0) + return ret; + } + if (ktime_compare(now, start)) + dev_dbg(wdev->dev, "answer after %lldus\n", + ktime_us_delta(now, start)); + + ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO + + (offs % DNLD_FIFO_SIZE), + data + offs, DNLD_BLOCK_SIZE); + if (ret < 0) + return ret; + + // WFx seems to not support writing 0 in this register during + // first loop + offs += DNLD_BLOCK_SIZE; + ret = sram_reg_write(wdev, WFX_DCA_PUT, offs); + if (ret < 0) + return ret; + } + return 0; +} + +static void print_boot_status(struct wfx_dev *wdev) +{ + u32 reg; + + sram_reg_read(wdev, WFX_STATUS_INFO, ®); + if (reg == 0x12345678) + return; + sram_reg_read(wdev, WFX_ERR_INFO, ®); + if (reg < ARRAY_SIZE(fwio_errors) && fwio_errors[reg]) + dev_info(wdev->dev, "secure boot: %s\n", fwio_errors[reg]); + else + dev_info(wdev->dev, "secure boot: Error %#02x\n", reg); +} + +static int load_firmware_secure(struct wfx_dev *wdev) +{ + const struct firmware *fw = NULL; + int header_size; + int fw_offset; + ktime_t start; + u8 *buf; + int ret; + + BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE); + buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY); + ret = wait_ncp_status(wdev, NCP_INFO_READY); + if (ret) + goto error; + + sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE); + buf[BOOTLOADER_LABEL_SIZE] = 0; + dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf); + + sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE); + ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset); + if (ret) + goto error; + header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE; + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ); + ret = wait_ncp_status(wdev, NCP_READY); + if (ret) + goto error; + + sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); // Fifo init + sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", + FW_VERSION_SIZE); + sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset, + FW_SIGNATURE_SIZE); + sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, + fw->data + fw_offset + FW_SIGNATURE_SIZE, + FW_HASH_SIZE); + sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size); + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING); + ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING); + if (ret) + goto error; + + start = ktime_get(); + ret = upload_firmware(wdev, fw->data + header_size, + fw->size - header_size); + if (ret) + goto error; + dev_dbg(wdev->dev, "firmware load after %lldus\n", + ktime_us_delta(ktime_get(), start)); + + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE); + ret = wait_ncp_status(wdev, NCP_AUTH_OK); + // Legacy ROM support + if (ret < 0) + ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY); + if (ret < 0) + goto error; + sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP); + +error: + kfree(buf); + if (fw) + release_firmware(fw); + if (ret) + print_boot_status(wdev); + return ret; +} + +static int init_gpr(struct wfx_dev *wdev) +{ + int ret, i; + static const struct { + int index; + u32 value; + } gpr_init[] = { + { 0x07, 0x208775 }, + { 0x08, 0x2EC020 }, + { 0x09, 0x3C3C3C }, + { 0x0B, 0x322C44 }, + { 0x0C, 0xA06497 }, + }; + + for (i = 0; i < ARRAY_SIZE(gpr_init); i++) { + ret = igpr_reg_write(wdev, gpr_init[i].index, + gpr_init[i].value); + if (ret < 0) + return ret; + dev_dbg(wdev->dev, " index %02x: %08x\n", + gpr_init[i].index, gpr_init[i].value); + } + return 0; +} + +int wfx_init_device(struct wfx_dev *wdev) +{ + int ret; + int hw_revision, hw_type; + int wakeup_timeout = 50; // ms + ktime_t now, start; + u32 reg; + + reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_BYTE_ORDER_ABCD; + if (wdev->pdata.use_rising_clk) + reg |= CFG_CLK_RISE_EDGE; + ret = config_reg_write(wdev, reg); + if (ret < 0) { + dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n"); + return -EIO; + } + + ret = config_reg_read(wdev, ®); + if (ret < 0) { + dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n"); + return -EIO; + } + if (reg == 0 || reg == ~0) { + dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n"); + return -EIO; + } + dev_dbg(wdev->dev, "initial config register value: %08x\n", reg); + + hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg); + if (hw_revision == 0) { + dev_err(wdev->dev, "bad hardware revision number: %d\n", + hw_revision); + return -ENODEV; + } + hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg); + if (hw_type == 1) { + dev_notice(wdev->dev, "development hardware detected\n"); + wakeup_timeout = 2000; + } + + ret = init_gpr(wdev); + if (ret < 0) + return ret; + + ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP); + if (ret < 0) + return -EIO; + start = ktime_get(); + for (;;) { + ret = control_reg_read(wdev, ®); + now = ktime_get(); + if (reg & CTRL_WLAN_READY) + break; + if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) { + dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n"); + return -ETIMEDOUT; + } + } + dev_dbg(wdev->dev, "chip wake up after %lldus\n", + ktime_us_delta(now, start)); + + ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0); + if (ret < 0) + return ret; + ret = load_firmware_secure(wdev); + if (ret < 0) + return ret; + return config_reg_write_bits(wdev, + CFG_DIRECT_ACCESS_MODE | + CFG_IRQ_ENABLE_DATA | + CFG_IRQ_ENABLE_WRDY, + CFG_IRQ_ENABLE_DATA); +} diff --git a/drivers/net/wireless/silabs/wfx/fwio.h b/drivers/net/wireless/silabs/wfx/fwio.h new file mode 100644 index 000000000000..6028f92503fe --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/fwio.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Firmware loading. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_FWIO_H +#define WFX_FWIO_H + +struct wfx_dev; + +int wfx_init_device(struct wfx_dev *wdev); + +#endif /* WFX_FWIO_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:55 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:55 +0100 Subject: [PATCH v3 12/24] wfx: add hif_api_*.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-13-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/hif_api_cmd.h | 553 ++++++++++++++++++ .../net/wireless/silabs/wfx/hif_api_general.h | 267 +++++++++ drivers/net/wireless/silabs/wfx/hif_api_mib.h | 343 +++++++++++ 3 files changed, 1163 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_cmd.h create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_general.h create mode 100644 drivers/net/wireless/silabs/wfx/hif_api_mib.h diff --git a/drivers/net/wireless/silabs/wfx/hif_api_cmd.h b/drivers/net/wireless/silabs/wfx/hif_api_cmd.h new file mode 100644 index 000000000000..11bc1a58edae --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_api_cmd.h @@ -0,0 +1,553 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2020, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_CMD_H +#define WFX_HIF_API_CMD_H + +#include + +#include "hif_api_general.h" + +enum hif_requests_ids { + HIF_REQ_ID_RESET = 0x0a, + HIF_REQ_ID_READ_MIB = 0x05, + HIF_REQ_ID_WRITE_MIB = 0x06, + HIF_REQ_ID_START_SCAN = 0x07, + HIF_REQ_ID_STOP_SCAN = 0x08, + HIF_REQ_ID_TX = 0x04, + HIF_REQ_ID_JOIN = 0x0b, + HIF_REQ_ID_SET_PM_MODE = 0x10, + HIF_REQ_ID_SET_BSS_PARAMS = 0x11, + HIF_REQ_ID_ADD_KEY = 0x0c, + HIF_REQ_ID_REMOVE_KEY = 0x0d, + HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_REQ_ID_START = 0x17, + HIF_REQ_ID_BEACON_TRANSMIT = 0x18, + HIF_REQ_ID_UPDATE_IE = 0x1b, + HIF_REQ_ID_MAP_LINK = 0x1c, +}; + +enum hif_confirmations_ids { + HIF_CNF_ID_RESET = 0x0a, + HIF_CNF_ID_READ_MIB = 0x05, + HIF_CNF_ID_WRITE_MIB = 0x06, + HIF_CNF_ID_START_SCAN = 0x07, + HIF_CNF_ID_STOP_SCAN = 0x08, + HIF_CNF_ID_TX = 0x04, + HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, + HIF_CNF_ID_JOIN = 0x0b, + HIF_CNF_ID_SET_PM_MODE = 0x10, + HIF_CNF_ID_SET_BSS_PARAMS = 0x11, + HIF_CNF_ID_ADD_KEY = 0x0c, + HIF_CNF_ID_REMOVE_KEY = 0x0d, + HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, + HIF_CNF_ID_START = 0x17, + HIF_CNF_ID_BEACON_TRANSMIT = 0x18, + HIF_CNF_ID_UPDATE_IE = 0x1b, + HIF_CNF_ID_MAP_LINK = 0x1c, +}; + +enum hif_indications_ids { + HIF_IND_ID_RX = 0x84, + HIF_IND_ID_SCAN_CMPL = 0x86, + HIF_IND_ID_JOIN_COMPLETE = 0x8f, + HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, + HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, + HIF_IND_ID_EVENT = 0x85 +}; + +struct hif_req_reset { + u8 reset_stat:1; + u8 reset_all_int:1; + u8 reserved1:6; + u8 reserved2[3]; +} __packed; + +struct hif_cnf_reset { + __le32 status; +} __packed; + +struct hif_req_read_mib { + __le16 mib_id; + __le16 reserved; +} __packed; + +struct hif_cnf_read_mib { + __le32 status; + __le16 mib_id; + __le16 length; + u8 mib_data[]; +} __packed; + +struct hif_req_write_mib { + __le16 mib_id; + __le16 length; + u8 mib_data[]; +} __packed; + +struct hif_cnf_write_mib { + __le32 status; +} __packed; + +struct hif_req_update_ie { + u8 beacon:1; + u8 probe_resp:1; + u8 probe_req:1; + u8 reserved1:5; + u8 reserved2; + __le16 num_ies; + struct element ie[]; +} __packed; + +struct hif_cnf_update_ie { + __le32 status; +} __packed; + +struct hif_ssid_def { + __le32 ssid_length; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +} __packed; + +#define HIF_API_MAX_NB_SSIDS 2 +#define HIF_API_MAX_NB_CHANNELS 14 + +struct hif_req_start_scan_alt { + u8 band; + u8 maintain_current_bss:1; + u8 periodic:1; + u8 reserved1:6; + u8 disallow_ps:1; + u8 reserved2:1; + u8 short_preamble:1; + u8 reserved3:5; + u8 max_transmit_rate; + __le16 periodic_interval; + u8 reserved4; + s8 periodic_rssi_thr; + u8 num_of_probe_requests; + u8 probe_delay; + u8 num_of_ssids; + u8 num_of_channels; + __le32 min_channel_time; + __le32 max_channel_time; + __le32 tx_power_level; // signed value + struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS]; + u8 channel_list[]; +} __packed; + +struct hif_cnf_start_scan { + __le32 status; +} __packed; + +struct hif_cnf_stop_scan { + __le32 status; +} __packed; + +enum hif_pm_mode_status { + HIF_PM_MODE_ACTIVE = 0x0, + HIF_PM_MODE_PS = 0x1, + HIF_PM_MODE_UNDETERMINED = 0x2 +}; + +struct hif_ind_scan_cmpl { + __le32 status; + u8 pm_mode; + u8 num_channels_completed; + __le16 reserved; +} __packed; + +enum hif_queue_id { + HIF_QUEUE_ID_BACKGROUND = 0x0, + HIF_QUEUE_ID_BESTEFFORT = 0x1, + HIF_QUEUE_ID_VIDEO = 0x2, + HIF_QUEUE_ID_VOICE = 0x3 +}; + +enum hif_frame_format { + HIF_FRAME_FORMAT_NON_HT = 0x0, + HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1, + HIF_FRAME_FORMAT_GF_HT_11N = 0x2 +}; + +struct hif_req_tx { + // packet_id is not interpreted by the device, so it is not necessary to + // declare it little endian + u32 packet_id; + u8 max_tx_rate; + u8 queue_id:2; + u8 peer_sta_id:4; + u8 reserved1:2; + u8 more:1; + u8 fc_offset:3; + u8 after_dtim:1; + u8 reserved2:3; + u8 start_exp:1; + u8 reserved3:3; + u8 retry_policy_index:4; + __le32 reserved4; + __le32 expire_time; + u8 frame_format:4; + u8 fec_coding:1; + u8 short_gi:1; + u8 reserved5:1; + u8 stbc:1; + u8 reserved6; + u8 aggregation:1; + u8 reserved7:7; + u8 reserved8; + u8 frame[]; +} __packed; + +enum hif_qos_ackplcy { + HIF_QOS_ACKPLCY_NORMAL = 0x0, + HIF_QOS_ACKPLCY_TXNOACK = 0x1, + HIF_QOS_ACKPLCY_NOEXPACK = 0x2, + HIF_QOS_ACKPLCY_BLCKACK = 0x3 +}; + +struct hif_cnf_tx { + __le32 status; + // packet_id is copied from struct hif_req_tx without been interpreted + // by the device, so it is not necessary to declare it little endian + u32 packet_id; + u8 txed_rate; + u8 ack_failures; + u8 aggr:1; + u8 requeue:1; + u8 ack_policy:2; + u8 txop_limit:1; + u8 reserved1:3; + u8 reserved2; + __le32 media_delay; + __le32 tx_queue_delay; +} __packed; + +struct hif_cnf_multi_transmit { + u8 num_tx_confs; + u8 reserved[3]; + struct hif_cnf_tx tx_conf_payload[]; +} __packed; + +enum hif_ri_flags_encrypt { + HIF_RI_FLAGS_UNENCRYPTED = 0x0, + HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1, + HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2, + HIF_RI_FLAGS_AES_ENCRYPTED = 0x3, + HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4 +}; + +struct hif_ind_rx { + __le32 status; + u8 channel_number; + u8 reserved1; + u8 rxed_rate; + u8 rcpi_rssi; + u8 encryp:3; + u8 in_aggr:1; + u8 first_aggr:1; + u8 last_aggr:1; + u8 defrag:1; + u8 beacon:1; + u8 tim:1; + u8 bitmap:1; + u8 match_ssid:1; + u8 match_bssid:1; + u8 more:1; + u8 reserved2:1; + u8 ht:1; + u8 stbc:1; + u8 match_uc_addr:1; + u8 match_mc_addr:1; + u8 match_bc_addr:1; + u8 key_type:1; + u8 key_index:4; + u8 reserved3:1; + u8 peer_sta_id:4; + u8 reserved4:2; + u8 reserved5:1; + u8 frame[]; +} __packed; + +struct hif_req_edca_queue_params { + u8 queue_id; + u8 reserved1; + u8 aifsn; + u8 reserved2; + __le16 cw_min; + __le16 cw_max; + __le16 tx_op_limit; + __le16 allowed_medium_time; + __le32 reserved3; +} __packed; + +struct hif_cnf_edca_queue_params { + __le32 status; +} __packed; + +struct hif_req_join { + u8 infrastructure_bss_mode:1; + u8 reserved1:7; + u8 band; + u8 channel_number; + u8 reserved2; + u8 bssid[ETH_ALEN]; + __le16 atim_window; + u8 short_preamble:1; + u8 reserved3:7; + u8 probe_for_join; + u8 reserved4; + u8 reserved5:2; + u8 force_no_beacon:1; + u8 force_with_ind:1; + u8 reserved6:4; + __le32 ssid_length; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + __le32 beacon_interval; + __le32 basic_rate_set; +} __packed; + +struct hif_cnf_join { + __le32 status; +} __packed; + +struct hif_ind_join_complete { + __le32 status; +} __packed; + +struct hif_req_set_bss_params { + u8 lost_count_only:1; + u8 reserved:7; + u8 beacon_lost_count; + __le16 aid; + __le32 operational_rate_set; +} __packed; + +struct hif_cnf_set_bss_params { + __le32 status; +} __packed; + +struct hif_req_set_pm_mode { + u8 enter_psm:1; + u8 reserved:6; + u8 fast_psm:1; + u8 fast_psm_idle_period; + u8 ap_psm_change_period; + u8 min_auto_ps_poll_period; +} __packed; + +struct hif_cnf_set_pm_mode { + __le32 status; +} __packed; + +struct hif_ind_set_pm_mode_cmpl { + __le32 status; + u8 pm_mode; + u8 reserved[3]; +} __packed; + +struct hif_req_start { + u8 mode; + u8 band; + u8 channel_number; + u8 reserved1; + __le32 reserved2; + __le32 beacon_interval; + u8 dtim_period; + u8 short_preamble:1; + u8 reserved3:7; + u8 reserved4; + u8 ssid_length; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + __le32 basic_rate_set; +} __packed; + +struct hif_cnf_start { + __le32 status; +} __packed; + +struct hif_req_beacon_transmit { + u8 enable_beaconing; + u8 reserved[3]; +} __packed; + +struct hif_cnf_beacon_transmit { + __le32 status; +} __packed; + +#define HIF_LINK_ID_MAX 14 +#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1) + +struct hif_req_map_link { + u8 mac_addr[ETH_ALEN]; + u8 unmap:1; + u8 mfpc:1; + u8 reserved:6; + u8 peer_sta_id; +} __packed; + +struct hif_cnf_map_link { + __le32 status; +} __packed; + +struct hif_ind_suspend_resume_tx { + u8 resume:1; + u8 reserved1:2; + u8 bc_mc_only:1; + u8 reserved2:4; + u8 reserved3; + __le16 peer_sta_set; +} __packed; + + +#define MAX_KEY_ENTRIES 24 +#define HIF_API_WEP_KEY_DATA_SIZE 16 +#define HIF_API_TKIP_KEY_DATA_SIZE 16 +#define HIF_API_RX_MIC_KEY_SIZE 8 +#define HIF_API_TX_MIC_KEY_SIZE 8 +#define HIF_API_AES_KEY_DATA_SIZE 16 +#define HIF_API_WAPI_KEY_DATA_SIZE 16 +#define HIF_API_MIC_KEY_DATA_SIZE 16 +#define HIF_API_IGTK_KEY_DATA_SIZE 16 +#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8 +#define HIF_API_IPN_SIZE 8 + +enum hif_key_type { + HIF_KEY_TYPE_WEP_DEFAULT = 0x0, + HIF_KEY_TYPE_WEP_PAIRWISE = 0x1, + HIF_KEY_TYPE_TKIP_GROUP = 0x2, + HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3, + HIF_KEY_TYPE_AES_GROUP = 0x4, + HIF_KEY_TYPE_AES_PAIRWISE = 0x5, + HIF_KEY_TYPE_WAPI_GROUP = 0x6, + HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7, + HIF_KEY_TYPE_IGTK_GROUP = 0x8, + HIF_KEY_TYPE_NONE = 0x9 +}; + +struct hif_wep_pairwise_key { + u8 peer_address[ETH_ALEN]; + u8 reserved; + u8 key_length; + u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; +} __packed; + +struct hif_wep_group_key { + u8 key_id; + u8 key_length; + u8 reserved[2]; + u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; +} __packed; + +struct hif_tkip_pairwise_key { + u8 peer_address[ETH_ALEN]; + u8 reserved[2]; + u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; +} __packed; + +struct hif_tkip_group_key { + u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; + u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; +} __packed; + +struct hif_aes_pairwise_key { + u8 peer_address[ETH_ALEN]; + u8 reserved[2]; + u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; +} __packed; + +struct hif_aes_group_key { + u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; +} __packed; + +struct hif_wapi_pairwise_key { + u8 peer_address[ETH_ALEN]; + u8 key_id; + u8 reserved; + u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; +} __packed; + +struct hif_wapi_group_key { + u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; + u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; +} __packed; + +struct hif_igtk_group_key { + u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; + u8 key_id; + u8 reserved[3]; + u8 ipn[HIF_API_IPN_SIZE]; +} __packed; + +struct hif_req_add_key { + u8 type; + u8 entry_index; + u8 int_id:2; + u8 reserved1:6; + u8 reserved2; + union { + struct hif_wep_pairwise_key wep_pairwise_key; + struct hif_wep_group_key wep_group_key; + struct hif_tkip_pairwise_key tkip_pairwise_key; + struct hif_tkip_group_key tkip_group_key; + struct hif_aes_pairwise_key aes_pairwise_key; + struct hif_aes_group_key aes_group_key; + struct hif_wapi_pairwise_key wapi_pairwise_key; + struct hif_wapi_group_key wapi_group_key; + struct hif_igtk_group_key igtk_group_key; + } key; +} __packed; + +struct hif_cnf_add_key { + __le32 status; +} __packed; + +struct hif_req_remove_key { + u8 entry_index; + u8 reserved[3]; +} __packed; + +struct hif_cnf_remove_key { + __le32 status; +} __packed; + +enum hif_event_ind { + HIF_EVENT_IND_BSSLOST = 0x1, + HIF_EVENT_IND_BSSREGAINED = 0x2, + HIF_EVENT_IND_RCPI_RSSI = 0x3, + HIF_EVENT_IND_PS_MODE_ERROR = 0x4, + HIF_EVENT_IND_INACTIVITY = 0x5 +}; + +enum hif_ps_mode_error { + HIF_PS_ERROR_NO_ERROR = 0, + HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1, + HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2, + HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3, + HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4 +}; + +struct hif_ind_event { + __le32 event_id; + union { + u8 rcpi_rssi; + __le32 ps_mode_error; + __le32 peer_sta_set; + } event_data; +} __packed; + +#endif diff --git a/drivers/net/wireless/silabs/wfx/hif_api_general.h b/drivers/net/wireless/silabs/wfx/hif_api_general.h new file mode 100644 index 000000000000..24188945718d --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_api_general.h @@ -0,0 +1,267 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2020, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_GENERAL_H +#define WFX_HIF_API_GENERAL_H + +#ifdef __KERNEL__ +#include +#include +#else +#include +#include +#define __packed __attribute__((__packed__)) +#endif + +#define HIF_ID_IS_INDICATION 0x80 +#define HIF_COUNTER_MAX 7 + +struct hif_msg { + __le16 len; + u8 id; + u8 reserved:1; + u8 interface:2; + u8 seqnum:3; + u8 encrypted:2; + u8 body[]; +} __packed; + +enum hif_general_requests_ids { + HIF_REQ_ID_CONFIGURATION = 0x09, + HIF_REQ_ID_CONTROL_GPIO = 0x26, + HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, + HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_REQ_ID_SL_CONFIGURE = 0x29, + HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, + HIF_REQ_ID_PTA_SETTINGS = 0x2b, + HIF_REQ_ID_PTA_PRIORITY = 0x2c, + HIF_REQ_ID_PTA_STATE = 0x2d, + HIF_REQ_ID_SHUT_DOWN = 0x32, +}; + +enum hif_general_confirmations_ids { + HIF_CNF_ID_CONFIGURATION = 0x09, + HIF_CNF_ID_CONTROL_GPIO = 0x26, + HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, + HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, + HIF_CNF_ID_SL_CONFIGURE = 0x29, + HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, + HIF_CNF_ID_PTA_SETTINGS = 0x2b, + HIF_CNF_ID_PTA_PRIORITY = 0x2c, + HIF_CNF_ID_PTA_STATE = 0x2d, + HIF_CNF_ID_SHUT_DOWN = 0x32, +}; + +enum hif_general_indications_ids { + HIF_IND_ID_EXCEPTION = 0xe0, + HIF_IND_ID_STARTUP = 0xe1, + HIF_IND_ID_WAKEUP = 0xe2, + HIF_IND_ID_GENERIC = 0xe3, + HIF_IND_ID_ERROR = 0xe4, + HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 +}; + +#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000)) +#define HIF_STATUS_FAIL (cpu_to_le32(0x0001)) +#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002)) +#define HIF_STATUS_WARNING (cpu_to_le32(0x0003)) +#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004)) +#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010)) +#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011)) +#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012)) +#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013)) +#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014)) +#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015)) +#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016)) +#define HIF_STATUS_BUSY (cpu_to_le32(0x0017)) +#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A)) +#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B)) +#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C)) +#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D)) +#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E)) +#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF)) +#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234)) +#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256)) + +enum hif_api_rate_index { + API_RATE_INDEX_B_1MBPS = 0, + API_RATE_INDEX_B_2MBPS = 1, + API_RATE_INDEX_B_5P5MBPS = 2, + API_RATE_INDEX_B_11MBPS = 3, + API_RATE_INDEX_PBCC_22MBPS = 4, + API_RATE_INDEX_PBCC_33MBPS = 5, + API_RATE_INDEX_G_6MBPS = 6, + API_RATE_INDEX_G_9MBPS = 7, + API_RATE_INDEX_G_12MBPS = 8, + API_RATE_INDEX_G_18MBPS = 9, + API_RATE_INDEX_G_24MBPS = 10, + API_RATE_INDEX_G_36MBPS = 11, + API_RATE_INDEX_G_48MBPS = 12, + API_RATE_INDEX_G_54MBPS = 13, + API_RATE_INDEX_N_6P5MBPS = 14, + API_RATE_INDEX_N_13MBPS = 15, + API_RATE_INDEX_N_19P5MBPS = 16, + API_RATE_INDEX_N_26MBPS = 17, + API_RATE_INDEX_N_39MBPS = 18, + API_RATE_INDEX_N_52MBPS = 19, + API_RATE_INDEX_N_58P5MBPS = 20, + API_RATE_INDEX_N_65MBPS = 21, + API_RATE_NUM_ENTRIES = 22 +}; + +enum hif_fw_type { + HIF_FW_TYPE_ETF = 0x0, + HIF_FW_TYPE_WFM = 0x1, + HIF_FW_TYPE_WSM = 0x2 +}; + +struct hif_ind_startup { + // As the others, this struct is interpreted as little endian by the + // device. However, this struct is also used by the driver. We prefer to + // declare it in native order and doing byte swap on reception. + __le32 status; + u16 hardware_id; + u8 opn[14]; + u8 uid[8]; + u16 num_inp_ch_bufs; + u16 size_inp_ch_buf; + u8 num_links_ap; + u8 num_interfaces; + u8 mac_addr[2][ETH_ALEN]; + u8 api_version_minor; + u8 api_version_major; + u8 link_mode:2; + u8 reserved1:6; + u8 reserved2; + u8 reserved3; + u8 reserved4; + u8 firmware_build; + u8 firmware_minor; + u8 firmware_major; + u8 firmware_type; + u8 disabled_channel_list[2]; + u8 region_sel_mode:4; + u8 reserved5:4; + u8 phy1_region:3; + u8 phy0_region:3; + u8 otp_phy_ver:2; + u32 supported_rate_mask; + u8 firmware_label[128]; +} __packed; + +struct hif_ind_wakeup { +} __packed; + +struct hif_req_configuration { + __le16 length; + u8 pds_data[]; +} __packed; + +struct hif_cnf_configuration { + __le32 status; +} __packed; + +enum hif_gpio_mode { + HIF_GPIO_MODE_D0 = 0x0, + HIF_GPIO_MODE_D1 = 0x1, + HIF_GPIO_MODE_OD0 = 0x2, + HIF_GPIO_MODE_OD1 = 0x3, + HIF_GPIO_MODE_TRISTATE = 0x4, + HIF_GPIO_MODE_TOGGLE = 0x5, + HIF_GPIO_MODE_READ = 0x6 +}; + +struct hif_req_control_gpio { + u8 gpio_label; + u8 gpio_mode; +} __packed; + +struct hif_cnf_control_gpio { + __le32 status; + __le32 value; +} __packed; + +enum hif_generic_indication_type { + HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, + HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, + HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2, + HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3, +}; + +struct hif_rx_stats { + __le32 nb_rx_frame; + __le32 nb_crc_frame; + __le32 per_total; + __le32 throughput; + __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES]; + __le16 per[API_RATE_NUM_ENTRIES]; + __le16 snr[API_RATE_NUM_ENTRIES]; // signed value + __le16 rssi[API_RATE_NUM_ENTRIES]; // signed value + __le16 cfo[API_RATE_NUM_ENTRIES]; // signed value + __le32 date; + __le32 pwr_clk_freq; + u8 is_ext_pwr_clk; + s8 current_temp; +} __packed; + +struct hif_tx_power_loop_info { + __le16 tx_gain_dig; + __le16 tx_gain_pa; + __le16 target_pout; // signed value + __le16 p_estimation; // signed value + __le16 vpdet; + u8 measurement_index; + u8 reserved; +} __packed; + +struct hif_ind_generic { + __le32 type; + union { + struct hif_rx_stats rx_stats; + struct hif_tx_power_loop_info tx_power_loop_info; + } data; +} __packed; + +enum hif_error { + HIF_ERROR_FIRMWARE_ROLLBACK = 0x00, + HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01, + HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02, + HIF_ERROR_SLK_SESSION_KEY = 0x03, + HIF_ERROR_OOR_VOLTAGE = 0x04, + HIF_ERROR_PDS_PAYLOAD = 0x05, + HIF_ERROR_OOR_TEMPERATURE = 0x06, + HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07, + HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08, + HIF_ERROR_SLK_OVERFLOW = 0x09, + HIF_ERROR_SLK_DECRYPTION = 0x0a, + HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b, + HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c, + HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e, + HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d, + HIF_ERROR_HIF_BUS = 0x0f, + HIF_ERROR_PDS_TESTFEATURE = 0x10, + HIF_ERROR_SLK_UNCONFIGURED = 0x11, +}; + +struct hif_ind_error { + __le32 type; + u8 data[]; +} __packed; + +struct hif_ind_exception { + __le32 type; + u8 data[]; +} __packed; + +enum hif_secure_link_state { + SEC_LINK_UNAVAILABLE = 0x0, + SEC_LINK_RESERVED = 0x1, + SEC_LINK_EVAL = 0x2, + SEC_LINK_ENFORCED = 0x3 +}; + +#endif diff --git a/drivers/net/wireless/silabs/wfx/hif_api_mib.h b/drivers/net/wireless/silabs/wfx/hif_api_mib.h new file mode 100644 index 000000000000..ace924720ce6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_api_mib.h @@ -0,0 +1,343 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* + * WFx hardware interface definitions + * + * Copyright (c) 2018-2020, Silicon Laboratories Inc. + */ + +#ifndef WFX_HIF_API_MIB_H +#define WFX_HIF_API_MIB_H + +#include "hif_api_general.h" + +#define HIF_API_IPV4_ADDRESS_SIZE 4 +#define HIF_API_IPV6_ADDRESS_SIZE 16 + +enum hif_mib_ids { + HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, + HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, + HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, + HIF_MIB_ID_CCA_CONFIG = 0x2003, + HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, + HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, + HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, + HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, + HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, + HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, + HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, + HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, + HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, + HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, + HIF_MIB_ID_RX_FILTER = 0x201B, + HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, + HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, + HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, + HIF_MIB_ID_TSF_COUNTER = 0x2031, + HIF_MIB_ID_STATISTICS_TABLE = 0x2032, + HIF_MIB_ID_COUNTERS_TABLE = 0x2033, + HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, + HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, + HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041, + HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, + HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, + HIF_MIB_ID_SLOT_TIME = 0x2045, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, + HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, + HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, + HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, + HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, + HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, + HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, + HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, + HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, + HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, + HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, + HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, + HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, + HIF_MIB_ID_BEACON_STATS = 0x2056, +}; + +enum hif_op_power_mode { + HIF_OP_POWER_MODE_ACTIVE = 0x0, + HIF_OP_POWER_MODE_DOZE = 0x1, + HIF_OP_POWER_MODE_QUIESCENT = 0x2 +}; + +struct hif_mib_gl_operational_power_mode { + u8 power_mode:4; + u8 reserved1:3; + u8 wup_ind_activation:1; + u8 reserved2[3]; +} __packed; + +struct hif_mib_gl_set_multi_msg { + u8 enable_multi_tx_conf:1; + u8 reserved1:7; + u8 reserved2[3]; +} __packed; + +enum hif_arp_ns_frame_treatment { + HIF_ARP_NS_FILTERING_DISABLE = 0x0, + HIF_ARP_NS_FILTERING_ENABLE = 0x1, + HIF_ARP_NS_REPLY_ENABLE = 0x2 +}; + +struct hif_mib_arp_ip_addr_table { + u8 condition_idx; + u8 arp_enable; + u8 reserved[2]; + u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; +} __packed; + +struct hif_mib_rx_filter { + u8 reserved1:1; + u8 bssid_filter:1; + u8 reserved2:1; + u8 fwd_probe_req:1; + u8 keep_alive_filter:1; + u8 reserved3:3; + u8 reserved4[3]; +} __packed; + +struct hif_ie_table_entry { + u8 ie_id; + u8 has_changed:1; + u8 no_longer:1; + u8 has_appeared:1; + u8 reserved:1; + u8 num_match_data:4; + u8 oui[3]; + u8 match_data[3]; +} __packed; + +struct hif_mib_bcn_filter_table { + __le32 num_of_info_elmts; + struct hif_ie_table_entry ie_table[]; +} __packed; + +enum hif_beacon_filter { + HIF_BEACON_FILTER_DISABLE = 0x0, + HIF_BEACON_FILTER_ENABLE = 0x1, + HIF_BEACON_FILTER_AUTO_ERP = 0x2 +}; + +struct hif_mib_bcn_filter_enable { + __le32 enable; + __le32 bcn_count; +} __packed; + +struct hif_mib_extended_count_table { + __le32 count_plcp_errors; + __le32 count_fcs_errors; + __le32 count_tx_packets; + __le32 count_rx_packets; + __le32 count_rx_packet_errors; + __le32 count_rx_decryption_failures; + __le32 count_rx_mic_failures; + __le32 count_rx_no_key_failures; + __le32 count_tx_multicast_frames; + __le32 count_tx_frames_success; + __le32 count_tx_frame_failures; + __le32 count_tx_frames_retried; + __le32 count_tx_frames_multi_retried; + __le32 count_rx_frame_duplicates; + __le32 count_rts_success; + __le32 count_rts_failures; + __le32 count_ack_failures; + __le32 count_rx_multicast_frames; + __le32 count_rx_frames_success; + __le32 count_rx_cmacicv_errors; + __le32 count_rx_cmac_replays; + __le32 count_rx_mgmt_ccmp_replays; + __le32 count_rx_bipmic_errors; + __le32 count_rx_beacon; + __le32 count_miss_beacon; + __le32 reserved[15]; +} __packed; + +struct hif_mib_count_table { + __le32 count_plcp_errors; + __le32 count_fcs_errors; + __le32 count_tx_packets; + __le32 count_rx_packets; + __le32 count_rx_packet_errors; + __le32 count_rx_decryption_failures; + __le32 count_rx_mic_failures; + __le32 count_rx_no_key_failures; + __le32 count_tx_multicast_frames; + __le32 count_tx_frames_success; + __le32 count_tx_frame_failures; + __le32 count_tx_frames_retried; + __le32 count_tx_frames_multi_retried; + __le32 count_rx_frame_duplicates; + __le32 count_rts_success; + __le32 count_rts_failures; + __le32 count_ack_failures; + __le32 count_rx_multicast_frames; + __le32 count_rx_frames_success; + __le32 count_rx_cmacicv_errors; + __le32 count_rx_cmac_replays; + __le32 count_rx_mgmt_ccmp_replays; + __le32 count_rx_bipmic_errors; +} __packed; + +struct hif_mib_mac_address { + u8 mac_addr[ETH_ALEN]; + __le16 reserved; +} __packed; + +struct hif_mib_wep_default_key_id { + u8 wep_default_key_id; + u8 reserved[3]; +} __packed; + +struct hif_mib_dot11_rts_threshold { + __le32 threshold; +} __packed; + +struct hif_mib_slot_time { + __le32 slot_time; +} __packed; + +struct hif_mib_current_tx_power_level { + __le32 power_level; // signed value +} __packed; + +struct hif_mib_non_erp_protection { + u8 use_cts_to_self:1; + u8 reserved1:7; + u8 reserved2[3]; +} __packed; + +enum hif_tmplt { + HIF_TMPLT_PRBREQ = 0x0, + HIF_TMPLT_BCN = 0x1, + HIF_TMPLT_NULL = 0x2, + HIF_TMPLT_QOSNUL = 0x3, + HIF_TMPLT_PSPOLL = 0x4, + HIF_TMPLT_PRBRES = 0x5, + HIF_TMPLT_ARP = 0x6, + HIF_TMPLT_NA = 0x7 +}; + +#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 + +struct hif_mib_template_frame { + u8 frame_type; + u8 init_rate:7; + u8 mode:1; + __le16 frame_length; + u8 frame[]; +} __packed; + +struct hif_mib_beacon_wake_up_period { + u8 wakeup_period_min; + u8 receive_dtim:1; + u8 reserved1:7; + u8 wakeup_period_max; + u8 reserved2; +} __packed; + +struct hif_mib_rcpi_rssi_threshold { + u8 detection:1; + u8 rcpi_rssi:1; + u8 upperthresh:1; + u8 lowerthresh:1; + u8 reserved:4; + u8 lower_threshold; + u8 upper_threshold; + u8 rolling_average_count; +} __packed; + +#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16 + +struct hif_mib_block_ack_policy { + u8 block_ack_tx_tid_policy; + u8 reserved1; + u8 block_ack_rx_tid_policy; + u8 block_ack_rx_max_buffer_size; +} __packed; + +enum hif_mpdu_start_spacing { + HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, + HIF_MPDU_START_SPACING_QUARTER = 0x1, + HIF_MPDU_START_SPACING_HALF = 0x2, + HIF_MPDU_START_SPACING_ONE = 0x3, + HIF_MPDU_START_SPACING_TWO = 0x4, + HIF_MPDU_START_SPACING_FOUR = 0x5, + HIF_MPDU_START_SPACING_EIGHT = 0x6, + HIF_MPDU_START_SPACING_SIXTEEN = 0x7 +}; + +struct hif_mib_set_association_mode { + u8 preambtype_use:1; + u8 mode:1; + u8 rateset:1; + u8 spacing:1; + u8 reserved1:4; + u8 short_preamble:1; + u8 reserved2:7; + u8 greenfield:1; + u8 reserved3:7; + u8 mpdu_start_spacing; + __le32 basic_rate_set; +} __packed; + +struct hif_mib_set_uapsd_information { + u8 trig_bckgrnd:1; + u8 trig_be:1; + u8 trig_video:1; + u8 trig_voice:1; + u8 reserved1:4; + u8 deliv_bckgrnd:1; + u8 deliv_be:1; + u8 deliv_video:1; + u8 deliv_voice:1; + u8 reserved2:4; + __le16 min_auto_trigger_interval; + __le16 max_auto_trigger_interval; + __le16 auto_trigger_step; +} __packed; + +struct hif_tx_rate_retry_policy { + u8 policy_index; + u8 short_retry_count; + u8 long_retry_count; + u8 first_rate_sel:2; + u8 terminate:1; + u8 count_init:1; + u8 reserved1:4; + u8 rate_recovery_count; + u8 reserved2[3]; + u8 rates[12]; +} __packed; + +#define HIF_TX_RETRY_POLICY_MAX 15 +#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX + +struct hif_mib_set_tx_rate_retry_policy { + u8 num_tx_rate_policies; + u8 reserved[3]; + struct hif_tx_rate_retry_policy tx_rate_retry_policy[]; +} __packed; + +struct hif_mib_protected_mgmt_policy { + u8 pmf_enable:1; + u8 unpmf_allowed:1; + u8 host_enc_auth_frames:1; + u8 reserved1:5; + u8 reserved2[3]; +} __packed; + +struct hif_mib_keep_alive_period { + __le16 keep_alive_period; + u8 reserved[2]; +} __packed; + +#endif -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:56 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:56 +0100 Subject: [PATCH v3 13/24] wfx: add hif_tx*.c/hif_tx*.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-14-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/hif_tx.c | 523 +++++++++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx.h | 60 +++ drivers/net/wireless/silabs/wfx/hif_tx_mib.c | 324 ++++++++++++ drivers/net/wireless/silabs/wfx/hif_tx_mib.h | 49 ++ 4 files changed, 956 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.c create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx.h create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.c create mode 100644 drivers/net/wireless/silabs/wfx/hif_tx_mib.h diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.c b/drivers/net/wireless/silabs/wfx/hif_tx.c new file mode 100644 index 000000000000..63b437261eb7 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.c @@ -0,0 +1,523 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx + * Split Mac (WSM) API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include + +#include "hif_tx.h" +#include "wfx.h" +#include "bh.h" +#include "hwio.h" +#include "debug.h" +#include "sta.h" + +void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) +{ + init_completion(&hif_cmd->ready); + init_completion(&hif_cmd->done); + mutex_init(&hif_cmd->lock); +} + +static void wfx_fill_header(struct hif_msg *hif, int if_id, + unsigned int cmd, size_t size) +{ + if (if_id == -1) + if_id = 2; + + WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd); + WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size); + WARN(if_id > 0x3, "invalid interface ID %d", if_id); + + hif->len = cpu_to_le16(size + 4); + hif->id = cmd; + hif->interface = if_id; +} + +static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif) +{ + *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL); + if (*hif) + return (*hif)->body; + else + return NULL; +} + +int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, + void *reply, size_t reply_len, bool no_reply) +{ + const char *mib_name = ""; + const char *mib_sep = ""; + int cmd = request->id; + int vif = request->interface; + int ret; + + // Do not wait for any reply if chip is frozen + if (wdev->chip_frozen) + return -ETIMEDOUT; + + mutex_lock(&wdev->hif_cmd.lock); + WARN(wdev->hif_cmd.buf_send, "data locking error"); + + // Note: call to complete() below has an implicit memory barrier that + // hopefully protect buf_send + wdev->hif_cmd.buf_send = request; + wdev->hif_cmd.buf_recv = reply; + wdev->hif_cmd.len_recv = reply_len; + complete(&wdev->hif_cmd.ready); + + wfx_bh_request_tx(wdev); + + if (no_reply) { + // Chip won't reply. Give enough time to the wq to send the + // buffer. + msleep(100); + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + return 0; + } + + if (wdev->poll_irq) + wfx_bh_poll_irq(wdev); + + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ); + if (!ret) { + dev_err(wdev->dev, "chip is abnormally long to answer\n"); + reinit_completion(&wdev->hif_cmd.ready); + ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ); + } + if (!ret) { + dev_err(wdev->dev, "chip did not answer\n"); + wfx_pending_dump_old_frames(wdev, 3000); + wdev->chip_frozen = true; + reinit_completion(&wdev->hif_cmd.done); + ret = -ETIMEDOUT; + } else { + ret = wdev->hif_cmd.ret; + } + + wdev->hif_cmd.buf_send = NULL; + mutex_unlock(&wdev->hif_cmd.lock); + + if (ret && + (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) { + mib_name = get_mib_name(((u16 *)request)[2]); + mib_sep = "/"; + } + if (ret < 0) + dev_err(wdev->dev, + "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n", + get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + if (ret > 0) + dev_warn(wdev->dev, + "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n", + get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); + + return ret; +} + +// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any +// request anymore. Obviously, only call this function during device unregister. +int hif_shutdown(struct wfx_dev *wdev) +{ + int ret; + struct hif_msg *hif; + + wfx_alloc_hif(0, &hif); + if (!hif) + return -ENOMEM; + wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0); + ret = wfx_cmd_send(wdev, hif, NULL, 0, true); + if (wdev->pdata.gpio_wakeup) + gpiod_set_value(wdev->pdata.gpio_wakeup, 0); + else + control_reg_write(wdev, 0); + kfree(hif); + return ret; +} + +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) +{ + int ret; + size_t buf_len = sizeof(struct hif_req_configuration) + len; + struct hif_msg *hif; + struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->length = cpu_to_le16(len); + memcpy(body->pds_data, conf, len); + wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_reset(struct wfx_vif *wvif, bool reset_stat) +{ + int ret; + struct hif_msg *hif; + struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->reset_stat = reset_stat; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_cnf_read_mib) + val_len; + struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); + struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL); + + if (!body || !reply) { + ret = -ENOMEM; + goto out; + } + body->mib_id = cpu_to_le16(mib_id); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, reply, buf_len, false); + + if (!ret && mib_id != le16_to_cpu(reply->mib_id)) { + dev_warn(wdev->dev, "%s: confirmation mismatch request\n", + __func__); + ret = -EIO; + } + if (ret == -ENOMEM) + dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", + get_mib_name(mib_id), val_len, + le16_to_cpu(reply->length)); + if (!ret) + memcpy(val, &reply->mib_data, le16_to_cpu(reply->length)); + else + memset(val, 0xFF, val_len); +out: + kfree(hif); + kfree(reply); + return ret; +} + +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *val, size_t val_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_write_mib) + val_len; + struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->mib_id = cpu_to_le16(mib_id); + body->length = cpu_to_le16(val_len); + memcpy(&body->mib_data, val, val_len); + wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, + int chan_start_idx, int chan_num, int *timeout) +{ + int ret, i; + struct hif_msg *hif; + size_t buf_len = + sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8); + struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif); + int tmo_chan_fg, tmo_chan_bg, tmo; + + WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params"); + WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params"); + + if (!hif) + return -ENOMEM; + for (i = 0; i < req->n_ssids; i++) { + memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, + IEEE80211_MAX_SSID_LEN); + body->ssid_def[i].ssid_length = + cpu_to_le32(req->ssids[i].ssid_len); + } + body->num_of_ssids = HIF_API_MAX_NB_SSIDS; + body->maintain_current_bss = 1; + body->disallow_ps = 1; + body->tx_power_level = + cpu_to_le32(req->channels[chan_start_idx]->max_power); + body->num_of_channels = chan_num; + for (i = 0; i < chan_num; i++) + body->channel_list[i] = + req->channels[i + chan_start_idx]->hw_value; + if (req->no_cck) + body->max_transmit_rate = API_RATE_INDEX_G_6MBPS; + else + body->max_transmit_rate = API_RATE_INDEX_B_1MBPS; + if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) { + body->min_channel_time = cpu_to_le32(50); + body->max_channel_time = cpu_to_le32(150); + } else { + body->min_channel_time = cpu_to_le32(10); + body->max_channel_time = cpu_to_le32(50); + body->num_of_probe_requests = 2; + body->probe_delay = 100; + } + tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU; + tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay; + tmo_chan_fg *= body->num_of_probe_requests; + tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU; + if (timeout) + *timeout = usecs_to_jiffies(tmo); + + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_stop_scan(struct wfx_vif *wvif) +{ + int ret; + struct hif_msg *hif; + // body associated to HIF_REQ_ID_STOP_SCAN is empty + wfx_alloc_hif(0, &hif); + + if (!hif) + return -ENOMEM; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen) +{ + int ret; + struct hif_msg *hif; + struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); + + WARN_ON(!conf->beacon_int); + WARN_ON(!conf->basic_rates); + WARN_ON(sizeof(body->ssid) < ssidlen); + WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS"); + if (WARN_ON(!channel)) + return -EINVAL; + if (!hif) + return -ENOMEM; + body->infrastructure_bss_mode = !conf->ibss_joined; + body->short_preamble = conf->use_short_preamble; + if (channel->flags & IEEE80211_CHAN_NO_IR) + body->probe_for_join = 0; + else + body->probe_for_join = 1; + body->channel_number = channel->hw_value; + body->beacon_interval = cpu_to_le32(conf->beacon_int); + body->basic_rate_set = + cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); + memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); + if (ssid) { + body->ssid_length = cpu_to_le32(ssidlen); + memcpy(body->ssid, ssid, ssidlen); + } + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count) +{ + int ret; + struct hif_msg *hif; + struct hif_req_set_bss_params *body = + wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->aid = cpu_to_le16(aid); + body->beacon_lost_count = beacon_lost_count; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, + sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg) +{ + int ret; + struct hif_msg *hif; + // FIXME: only send necessary bits + struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + // FIXME: swap bytes as necessary in body + memcpy(body, arg, sizeof(*body)); + if (wfx_api_older_than(wdev, 1, 5)) + // Legacy firmwares expect that add_key to be sent on right + // interface. + wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, + sizeof(*body)); + else + wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_remove_key(struct wfx_dev *wdev, int idx) +{ + int ret; + struct hif_msg *hif; + struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + body->entry_index = idx; + wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body)); + ret = wfx_cmd_send(wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg) +{ + int ret; + struct hif_msg *hif; + struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), + &hif); + + if (!body) + return -ENOMEM; + + WARN_ON(arg->aifs > 255); + if (!hif) + return -ENOMEM; + body->aifsn = arg->aifs; + body->cw_min = cpu_to_le16(arg->cw_min); + body->cw_max = cpu_to_le16(arg->cw_max); + body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP); + body->queue_id = 3 - queue; + // API 2.0 has changed queue IDs values + if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE) + body->queue_id = HIF_QUEUE_ID_BACKGROUND; + if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK) + body->queue_id = HIF_QUEUE_ID_BESTEFFORT; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, + sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) +{ + int ret; + struct hif_msg *hif; + struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!body) + return -ENOMEM; + + if (!hif) + return -ENOMEM; + if (ps) { + body->enter_psm = 1; + // Firmware does not support more than 128ms + body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255); + if (body->fast_psm_idle_period) + body->fast_psm = 1; + } + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel) +{ + int ret; + struct hif_msg *hif; + struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); + + WARN_ON(!conf->beacon_int); + if (!hif) + return -ENOMEM; + body->dtim_period = conf->dtim_period; + body->short_preamble = conf->use_short_preamble; + body->channel_number = channel->hw_value; + body->beacon_interval = cpu_to_le32(conf->beacon_int); + body->basic_rate_set = + cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); + body->ssid_length = conf->ssid_len; + memcpy(body->ssid, conf->ssid, conf->ssid_len); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_beacon_transmit(struct wfx_vif *wvif, bool enable) +{ + int ret; + struct hif_msg *hif; + struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), + &hif); + + if (!hif) + return -ENOMEM; + body->enable_beaconing = enable ? 1 : 0; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, + sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp) +{ + int ret; + struct hif_msg *hif; + struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif); + + if (!hif) + return -ENOMEM; + if (mac_addr) + ether_addr_copy(body->mac_addr, mac_addr); + body->mfpc = mfp ? 1 : 0; + body->unmap = unmap ? 1 : 0; + body->peer_sta_id = sta_id; + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body)); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} + +int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) +{ + int ret; + struct hif_msg *hif; + int buf_len = sizeof(struct hif_req_update_ie) + ies_len; + struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif); + + if (!hif) + return -ENOMEM; + body->beacon = 1; + body->num_ies = cpu_to_le16(1); + memcpy(body->ie, ies, ies_len); + wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len); + ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); + kfree(hif); + return ret; +} diff --git a/drivers/net/wireless/silabs/wfx/hif_tx.h b/drivers/net/wireless/silabs/wfx/hif_tx.h new file mode 100644 index 000000000000..3521c545ae6b --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx + * Split Mac (WSM) API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_H +#define WFX_HIF_TX_H + +struct ieee80211_channel; +struct ieee80211_bss_conf; +struct ieee80211_tx_queue_params; +struct cfg80211_scan_request; +struct hif_req_add_key; +struct wfx_dev; +struct wfx_vif; + +struct wfx_hif_cmd { + struct mutex lock; + struct completion ready; + struct completion done; + struct hif_msg *buf_send; + void *buf_recv; + size_t len_recv; + int ret; +}; + +void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd); +int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, + void *reply, size_t reply_len, bool async); + +int hif_shutdown(struct wfx_dev *wdev); +int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len); +int hif_reset(struct wfx_vif *wvif, bool reset_stat); +int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, + void *buf, size_t buf_size); +int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211, + int chan_start, int chan_num, int *timeout); +int hif_stop_scan(struct wfx_vif *wvif); +int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); +int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); +int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count); +int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg); +int hif_remove_key(struct wfx_dev *wdev, int idx); +int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, + const struct ieee80211_tx_queue_params *arg); +int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, + const struct ieee80211_channel *channel); +int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); +int hif_map_link(struct wfx_vif *wvif, + bool unmap, u8 *mac_addr, int sta_id, bool mfp); +int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); + +#endif diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.c b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c new file mode 100644 index 000000000000..1926cf1b62be --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.c @@ -0,0 +1,324 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ + +#include + +#include "wfx.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" +#include "hif_api_mib.h" + +int hif_set_output_power(struct wfx_vif *wvif, int val) +{ + struct hif_mib_current_tx_power_level arg = { + .power_level = cpu_to_le32(val * 10), + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, + &arg, sizeof(arg)); +} + +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval) +{ + struct hif_mib_beacon_wake_up_period arg = { + .wakeup_period_min = dtim_interval, + .receive_dtim = 0, + .wakeup_period_max = listen_interval, + }; + + if (dtim_interval > 0xFF || listen_interval > 0xFFFF) + return -EINVAL; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_WAKEUP_PERIOD, + &arg, sizeof(arg)); +} + +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst) +{ + struct hif_mib_rcpi_rssi_threshold arg = { + .rolling_average_count = 8, + .detection = 1, + }; + + if (!rssi_thold && !rssi_hyst) { + arg.upperthresh = 1; + arg.lowerthresh = 1; + } else { + arg.upper_threshold = rssi_thold + rssi_hyst; + arg.upper_threshold = (arg.upper_threshold + 110) * 2; + arg.lower_threshold = rssi_thold; + arg.lower_threshold = (arg.lower_threshold + 110) * 2; + } + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg)); +} + +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct hif_mib_extended_count_table *arg) +{ + if (wfx_api_older_than(wdev, 1, 3)) { + // extended_count_table is wider than count_table + memset(arg, 0xFF, sizeof(*arg)); + return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, + arg, sizeof(struct hif_mib_count_table)); + } else { + return hif_read_mib(wdev, vif_id, + HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg, + sizeof(struct hif_mib_extended_count_table)); + } +} + +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) +{ + struct hif_mib_mac_address msg = { }; + + if (mac) + ether_addr_copy(msg.mac_addr, mac); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, + &msg, sizeof(msg)); +} + +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool filter_prbreq) +{ + struct hif_mib_rx_filter arg = { }; + + if (filter_bssid) + arg.bssid_filter = 1; + if (!filter_prbreq) + arg.fwd_probe_req = 1; + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, + &arg, sizeof(arg)); +} + +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl) +{ + int ret; + struct hif_mib_bcn_filter_table *arg; + int buf_len = struct_size(arg, ie_table, tbl_len); + + arg = kzalloc(buf_len, GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->num_of_info_elmts = cpu_to_le32(tbl_len); + memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len)); + ret = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len); + kfree(arg); + return ret; +} + +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count) +{ + struct hif_mib_bcn_filter_enable arg = { + .enable = cpu_to_le32(enable), + .bcn_count = cpu_to_le32(beacon_count), + }; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_BEACON_FILTER_ENABLE, + &arg, sizeof(arg)); +} + +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode) +{ + struct hif_mib_gl_operational_power_mode arg = { + .power_mode = mode, + .wup_ind_activation = 1, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, + &arg, sizeof(arg)); +} + +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate) +{ + struct hif_mib_template_frame *arg; + + WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); + skb_push(skb, 4); + arg = (struct hif_mib_template_frame *)skb->data; + skb_pull(skb, 4); + arg->init_rate = init_rate; + arg->frame_type = frame_type; + arg->frame_length = cpu_to_le16(skb->len); + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, + arg, sizeof(*arg) + skb->len); +} + +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) +{ + struct hif_mib_protected_mgmt_policy arg = { }; + + WARN(required && !capable, "incoherent arguments"); + if (capable) { + arg.pmf_enable = 1; + arg.host_enc_auth_frames = 1; + } + if (!required) + arg.unpmf_allowed = 1; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_PROTECTED_MGMT_POLICY, + &arg, sizeof(arg)); +} + +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy) +{ + struct hif_mib_block_ack_policy arg = { + .block_ack_tx_tid_policy = tx_tid_policy, + .block_ack_rx_tid_policy = rx_tid_policy, + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, + &arg, sizeof(arg)); +} + +int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble) +{ + struct hif_mib_set_association_mode arg = { + .preambtype_use = 1, + .mode = 1, + .spacing = 1, + .short_preamble = short_preamble, + .greenfield = greenfield, + .mpdu_start_spacing = ampdu_density, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg)); +} + +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates) +{ + struct hif_mib_set_tx_rate_retry_policy *arg; + size_t size = struct_size(arg, tx_rate_retry_policy, 1); + int ret; + + arg = kzalloc(size, GFP_KERNEL); + if (!arg) + return -ENOMEM; + arg->num_tx_rate_policies = 1; + arg->tx_rate_retry_policy[0].policy_index = policy_index; + arg->tx_rate_retry_policy[0].short_retry_count = 255; + arg->tx_rate_retry_policy[0].long_retry_count = 255; + arg->tx_rate_retry_policy[0].first_rate_sel = 1; + arg->tx_rate_retry_policy[0].terminate = 1; + arg->tx_rate_retry_policy[0].count_init = 1; + memcpy(&arg->tx_rate_retry_policy[0].rates, rates, + sizeof(arg->tx_rate_retry_policy[0].rates)); + ret = hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); + kfree(arg); + return ret; +} + +int hif_keep_alive_period(struct wfx_vif *wvif, int period) +{ + struct hif_mib_keep_alive_period arg = { + .keep_alive_period = cpu_to_le16(period), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, + &arg, sizeof(arg)); +}; + +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) +{ + struct hif_mib_arp_ip_addr_table arg = { + .condition_idx = idx, + .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, + }; + + if (addr) { + // Caution: type of addr is __be32 + memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); + arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; + } + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, + &arg, sizeof(arg)); +} + +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) +{ + struct hif_mib_gl_set_multi_msg arg = { + .enable_multi_tx_conf = enable, + }; + + return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, + &arg, sizeof(arg)); +} + +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) +{ + struct hif_mib_set_uapsd_information arg = { }; + + if (val & BIT(IEEE80211_AC_VO)) + arg.trig_voice = 1; + if (val & BIT(IEEE80211_AC_VI)) + arg.trig_video = 1; + if (val & BIT(IEEE80211_AC_BE)) + arg.trig_be = 1; + if (val & BIT(IEEE80211_AC_BK)) + arg.trig_bckgrnd = 1; + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_SET_UAPSD_INFORMATION, + &arg, sizeof(arg)); +} + +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) +{ + struct hif_mib_non_erp_protection arg = { + .use_cts_to_self = enable, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); +} + +int hif_slot_time(struct wfx_vif *wvif, int val) +{ + struct hif_mib_slot_time arg = { + .slot_time = cpu_to_le32(val), + }; + + return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, + &arg, sizeof(arg)); +} + +int hif_wep_default_key_id(struct wfx_vif *wvif, int val) +{ + struct hif_mib_wep_default_key_id arg = { + .wep_default_key_id = val, + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, + &arg, sizeof(arg)); +} + +int hif_rts_threshold(struct wfx_vif *wvif, int val) +{ + struct hif_mib_dot11_rts_threshold arg = { + .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), + }; + + return hif_write_mib(wvif->wdev, wvif->id, + HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg)); +} diff --git a/drivers/net/wireless/silabs/wfx/hif_tx_mib.h b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h new file mode 100644 index 000000000000..812b3ba0f00e --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_tx_mib.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_TX_MIB_H +#define WFX_HIF_TX_MIB_H + +struct wfx_vif; +struct sk_buff; + +int hif_set_output_power(struct wfx_vif *wvif, int val); +int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, + unsigned int dtim_interval, + unsigned int listen_interval); +int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, + int rssi_thold, int rssi_hyst); +int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, + struct hif_mib_extended_count_table *arg); +int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac); +int hif_set_rx_filter(struct wfx_vif *wvif, + bool filter_bssid, bool fwd_probe_req); +int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, + const struct hif_ie_table_entry *tbl); +int hif_beacon_filter_control(struct wfx_vif *wvif, + int enable, int beacon_count); +int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode); +int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, + u8 frame_type, int init_rate); +int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required); +int hif_set_block_ack_policy(struct wfx_vif *wvif, + u8 tx_tid_policy, u8 rx_tid_policy); +int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, + bool greenfield, bool short_preamble); +int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, + int policy_index, u8 *rates); +int hif_keep_alive_period(struct wfx_vif *wvif, int period); +int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr); +int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable); +int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val); +int hif_erp_use_protection(struct wfx_vif *wvif, bool enable); +int hif_slot_time(struct wfx_vif *wvif, int val); +int hif_wep_default_key_id(struct wfx_vif *wvif, int val); +int hif_rts_threshold(struct wfx_vif *wvif, int val); + +#endif -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:57 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:57 +0100 Subject: [PATCH v3 14/24] wfx: add key.c/key.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-15-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/key.c | 241 ++++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/key.h | 20 +++ 2 files changed, 261 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/key.c create mode 100644 drivers/net/wireless/silabs/wfx/key.h diff --git a/drivers/net/wireless/silabs/wfx/key.c b/drivers/net/wireless/silabs/wfx/key.c new file mode 100644 index 000000000000..2ab82bed4c1b --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/key.c @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Key management related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "key.h" +#include "wfx.h" +#include "hif_tx_mib.h" + +static int wfx_alloc_key(struct wfx_dev *wdev) +{ + int idx; + + idx = ffs(~wdev->key_map) - 1; + if (idx < 0 || idx >= MAX_KEY_ENTRIES) + return -1; + + wdev->key_map |= BIT(idx); + return idx; +} + +static void wfx_free_key(struct wfx_dev *wdev, int idx) +{ + WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); + wdev->key_map &= ~BIT(idx); +} + +static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_WEP_PAIRWISE; +} + +static u8 fill_wep_group(struct hif_wep_group_key *msg, + struct ieee80211_key_conf *key) +{ + WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); + msg->key_id = key->keyidx; + msg->key_length = key->keylen; + memcpy(msg->key_data, key->key, key->keylen); + return HIF_KEY_TYPE_WEP_DEFAULT; +} + +static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + sizeof(msg->tx_mic_key) + + sizeof(msg->rx_mic_key), "inconsistent data"); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); + keybuf += sizeof(msg->tx_mic_key); + memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); + ether_addr_copy(msg->peer_address, peer_addr); + return HIF_KEY_TYPE_TKIP_PAIRWISE; +} + +static u8 fill_tkip_group(struct hif_tkip_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq, + enum nl80211_iftype iftype) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->tkip_key_data) + + 2 * sizeof(msg->rx_mic_key), "inconsistent data"); + msg->key_id = key->keyidx; + memcpy(msg->rx_sequence_counter, + &seq->tkip.iv16, sizeof(seq->tkip.iv16)); + memcpy(msg->rx_sequence_counter + sizeof(u16), + &seq->tkip.iv32, sizeof(seq->tkip.iv32)); + memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); + keybuf += sizeof(msg->tkip_key_data); + if (iftype == NL80211_IFTYPE_AP) + // Use Tx MIC Key + memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); + else + // Use Rx MIC Key + memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); + return HIF_KEY_TYPE_TKIP_GROUP; +} + +static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->aes_key_data, key->key, key->keylen); + return HIF_KEY_TYPE_AES_PAIRWISE; +} + +static u8 fill_ccmp_group(struct hif_aes_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); + memcpy(msg->aes_key_data, key->key, key->keylen); + memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); + memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_AES_GROUP; +} + +static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg, + struct ieee80211_key_conf *key, u8 *peer_addr) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + ether_addr_copy(msg->peer_address, peer_addr); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_PAIRWISE; +} + +static u8 fill_sms4_group(struct hif_wapi_group_key *msg, + struct ieee80211_key_conf *key) +{ + u8 *keybuf = key->key; + + WARN(key->keylen != sizeof(msg->wapi_key_data) + + sizeof(msg->mic_key_data), "inconsistent data"); + memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); + keybuf += sizeof(msg->wapi_key_data); + memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_WAPI_GROUP; +} + +static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg, + struct ieee80211_key_conf *key, + struct ieee80211_key_seq *seq) +{ + WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); + memcpy(msg->igtk_key_data, key->key, key->keylen); + memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); + memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); + msg->key_id = key->keyidx; + return HIF_KEY_TYPE_IGTK_GROUP; +} + +static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret; + struct hif_req_add_key k = { }; + struct ieee80211_key_seq seq; + struct wfx_dev *wdev = wvif->wdev; + int idx = wfx_alloc_key(wvif->wdev); + bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; + + WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); + ieee80211_get_key_rx_seq(key, 0, &seq); + if (idx < 0) + return -EINVAL; + k.int_id = wvif->id; + k.entry_index = idx; + if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || + key->cipher == WLAN_CIPHER_SUITE_WEP104) { + if (pairwise) + k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, + sta->addr); + else + k.type = fill_wep_group(&k.key.wep_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { + if (pairwise) + k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, + sta->addr); + else + k.type = fill_tkip_group(&k.key.tkip_group_key, key, + &seq, wvif->vif->type); + } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { + if (pairwise) + k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, + sta->addr); + else + k.type = fill_ccmp_group(&k.key.aes_group_key, key, + &seq); + } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { + if (pairwise) + k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, + sta->addr); + else + k.type = fill_sms4_group(&k.key.wapi_group_key, key); + } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { + k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq); + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; + } else { + dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + ret = hif_add_key(wdev, &k); + if (ret) { + wfx_free_key(wdev, idx); + return -EOPNOTSUPP; + } + key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | + IEEE80211_KEY_FLAG_RESERVE_TAILROOM; + key->hw_key_idx = idx; + return 0; +} + +static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) +{ + WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); + wfx_free_key(wvif->wdev, key->hw_key_idx); + return hif_remove_key(wvif->wdev, key->hw_key_idx); +} + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key) +{ + int ret = -EOPNOTSUPP; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + mutex_lock(&wvif->wdev->conf_mutex); + if (cmd == SET_KEY) + ret = wfx_add_key(wvif, sta, key); + if (cmd == DISABLE_KEY) + ret = wfx_remove_key(wvif, key); + mutex_unlock(&wvif->wdev->conf_mutex); + return ret; +} + diff --git a/drivers/net/wireless/silabs/wfx/key.h b/drivers/net/wireless/silabs/wfx/key.h new file mode 100644 index 000000000000..70a44d0ca35e --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/key.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_KEY_H +#define WFX_KEY_H + +#include + +struct wfx_dev; +struct wfx_vif; + +int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, + struct ieee80211_vif *vif, struct ieee80211_sta *sta, + struct ieee80211_key_conf *key); + +#endif /* WFX_STA_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:58 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:58 +0100 Subject: [PATCH v3 15/24] wfx: add hif_rx.c/hif_rx.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-16-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/hif_rx.c | 415 +++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/hif_rx.h | 18 + 2 files changed, 433 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/hif_rx.c create mode 100644 drivers/net/wireless/silabs/wfx/hif_rx.h diff --git a/drivers/net/wireless/silabs/wfx/hif_rx.c b/drivers/net/wireless/silabs/wfx/hif_rx.c new file mode 100644 index 000000000000..56a5f891447b --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_rx.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac + * (WSM) API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "hif_rx.h" +#include "wfx.h" +#include "scan.h" +#include "bh.h" +#include "sta.h" +#include "data_rx.h" +#include "hif_api_cmd.h" + +static int hif_generic_confirm(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + // All confirm messages start with status + int status = le32_to_cpup((__le32 *)buf); + int cmd = hif->id; + int len = le16_to_cpu(hif->len) - 4; // drop header + + WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); + + if (!wdev->hif_cmd.buf_send) { + dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd); + return -EINVAL; + } + + if (cmd != wdev->hif_cmd.buf_send->id) { + dev_warn(wdev->dev, + "chip response mismatch request: 0x%.2x vs 0x%.2x\n", + cmd, wdev->hif_cmd.buf_send->id); + return -EINVAL; + } + + if (wdev->hif_cmd.buf_recv) { + if (wdev->hif_cmd.len_recv >= len && len > 0) + memcpy(wdev->hif_cmd.buf_recv, buf, len); + else + status = -EIO; + } + wdev->hif_cmd.ret = status; + + complete(&wdev->hif_cmd.done); + return status; +} + +static int hif_tx_confirm(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_cnf_tx *body = buf; + + wfx_tx_confirm_cb(wdev, body); + return 0; +} + +static int hif_multi_tx_confirm(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_cnf_multi_transmit *body = buf; + int i; + + WARN(body->num_tx_confs <= 0, "corrupted message"); + for (i = 0; i < body->num_tx_confs; i++) + wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]); + return 0; +} + +static int hif_startup_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_ind_startup *body = buf; + + if (body->status || body->firmware_type > 4) { + dev_err(wdev->dev, "received invalid startup indication"); + return -EINVAL; + } + memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup)); + le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id); + le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs); + le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf); + le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask); + + complete(&wdev->firmware_ready); + return 0; +} + +static int hif_wakeup_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + if (!wdev->pdata.gpio_wakeup || + gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) { + dev_warn(wdev->dev, "unexpected wake-up indication\n"); + return -EIO; + } + return 0; +} + +static int hif_receive_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, + const void *buf, struct sk_buff *skb) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + const struct hif_ind_rx *body = buf; + + if (!wvif) { + dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n", + __func__, hif->interface); + return -EIO; + } + skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx)); + wfx_rx_cb(wvif, body, skb); + + return 0; +} + +static int hif_event_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + const struct hif_ind_event *body = buf; + int type = le32_to_cpu(body->event_id); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + + switch (type) { + case HIF_EVENT_IND_RCPI_RSSI: + wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi); + break; + case HIF_EVENT_IND_BSSLOST: + schedule_delayed_work(&wvif->beacon_loss_work, 0); + break; + case HIF_EVENT_IND_BSSREGAINED: + cancel_delayed_work(&wvif->beacon_loss_work); + dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n"); + break; + case HIF_EVENT_IND_PS_MODE_ERROR: + dev_warn(wdev->dev, "error while processing power save request: %d\n", + le32_to_cpu(body->event_data.ps_mode_error)); + break; + default: + dev_warn(wdev->dev, "unhandled event indication: %.2x\n", + type); + break; + } + return 0; +} + +static int hif_pm_mode_complete_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, + const void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + complete(&wvif->set_pm_mode_complete); + + return 0; +} + +static int hif_scan_complete_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, + const void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + + wfx_scan_complete(wvif); + + return 0; +} + +static int hif_join_complete_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, + const void *buf) +{ + struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + dev_warn(wdev->dev, "unattended JoinCompleteInd\n"); + + return 0; +} + +static int hif_suspend_resume_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, + const void *buf) +{ + const struct hif_ind_suspend_resume_tx *body = buf; + struct wfx_vif *wvif; + + if (body->bc_mc_only) { + wvif = wdev_to_wvif(wdev, hif->interface); + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + if (body->resume) + wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); + else + wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); + } else { + WARN(body->peer_sta_set, "misunderstood indication"); + WARN(hif->interface != 2, "misunderstood indication"); + if (body->resume) + wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE); + else + wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP); + } + + return 0; +} + +static int hif_generic_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_ind_generic *body = buf; + int type = le32_to_cpu(body->type); + + switch (type) { + case HIF_GENERIC_INDICATION_TYPE_RAW: + return 0; + case HIF_GENERIC_INDICATION_TYPE_STRING: + dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data); + return 0; + case HIF_GENERIC_INDICATION_TYPE_RX_STATS: + mutex_lock(&wdev->rx_stats_lock); + // Older firmware send a generic indication beside RxStats + if (!wfx_api_older_than(wdev, 1, 4)) + dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n", + body->data.rx_stats.current_temp); + memcpy(&wdev->rx_stats, &body->data.rx_stats, + sizeof(wdev->rx_stats)); + mutex_unlock(&wdev->rx_stats_lock); + return 0; + case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO: + mutex_lock(&wdev->tx_power_loop_info_lock); + memcpy(&wdev->tx_power_loop_info, + &body->data.tx_power_loop_info, + sizeof(wdev->tx_power_loop_info)); + mutex_unlock(&wdev->tx_power_loop_info_lock); + return 0; + default: + dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n", + type); + return -EIO; + } +} + +static const struct { + int val; + const char *str; + bool has_param; +} hif_errors[] = { + { HIF_ERROR_FIRMWARE_ROLLBACK, + "rollback status" }, + { HIF_ERROR_FIRMWARE_DEBUG_ENABLED, + "debug feature enabled" }, + { HIF_ERROR_PDS_PAYLOAD, + "PDS version is not supported" }, + { HIF_ERROR_PDS_TESTFEATURE, + "PDS ask for an unknown test mode" }, + { HIF_ERROR_OOR_VOLTAGE, + "out-of-range power supply voltage", true }, + { HIF_ERROR_OOR_TEMPERATURE, + "out-of-range temperature", true }, + { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE, + "secure link does not expect request during key exchange" }, + { HIF_ERROR_SLK_SESSION_KEY, + "secure link session key is invalid" }, + { HIF_ERROR_SLK_OVERFLOW, + "secure link overflow" }, + { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE, + "secure link messages list does not match message encryption" }, + { HIF_ERROR_SLK_UNCONFIGURED, + "secure link not yet configured" }, + { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW, + "bus clock is too slow (<1kHz)" }, + { HIF_ERROR_HIF_RX_DATA_TOO_LARGE, + "HIF message too large" }, + // Following errors only exists in old firmware versions: + { HIF_ERROR_HIF_TX_QUEUE_FULL, + "HIF messages queue is full" }, + { HIF_ERROR_HIF_BUS, + "HIF bus" }, + { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED, + "secure link does not support multi-tx confirmations" }, + { HIF_ERROR_SLK_OUTDATED_SESSION_KEY, + "secure link session key is outdated" }, + { HIF_ERROR_SLK_DECRYPTION, + "secure link params (nonce or tag) mismatch" }, +}; + +static int hif_error_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_ind_error *body = buf; + int type = le32_to_cpu(body->type); + int param = (s8)body->data[0]; + int i; + + for (i = 0; i < ARRAY_SIZE(hif_errors); i++) + if (type == hif_errors[i].val) + break; + if (i < ARRAY_SIZE(hif_errors)) + if (hif_errors[i].has_param) + dev_err(wdev->dev, "asynchronous error: %s: %d\n", + hif_errors[i].str, param); + else + dev_err(wdev->dev, "asynchronous error: %s\n", + hif_errors[i].str); + else + dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, + 16, 1, hif, le16_to_cpu(hif->len), false); + wdev->chip_frozen = true; + + return 0; +}; + +static int hif_exception_indication(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf) +{ + const struct hif_ind_exception *body = buf; + int type = le32_to_cpu(body->type); + + if (type == 4) + dev_err(wdev->dev, "firmware assert %d\n", + le32_to_cpup((__le32 *)body->data)); + else + dev_err(wdev->dev, "firmware exception\n"); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, + 16, 1, hif, le16_to_cpu(hif->len), false); + wdev->chip_frozen = true; + + return -1; +} + +static const struct { + int msg_id; + int (*handler)(struct wfx_dev *wdev, + const struct hif_msg *hif, const void *buf); +} hif_handlers[] = { + /* Confirmations */ + { HIF_CNF_ID_TX, hif_tx_confirm }, + { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm }, + /* Indications */ + { HIF_IND_ID_STARTUP, hif_startup_indication }, + { HIF_IND_ID_WAKEUP, hif_wakeup_indication }, + { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication }, + { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication }, + { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication }, + { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication }, + { HIF_IND_ID_EVENT, hif_event_indication }, + { HIF_IND_ID_GENERIC, hif_generic_indication }, + { HIF_IND_ID_ERROR, hif_error_indication }, + { HIF_IND_ID_EXCEPTION, hif_exception_indication }, + // FIXME: allocate skb_p from hif_receive_indication and make it generic + //{ HIF_IND_ID_RX, hif_receive_indication }, +}; + +void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) +{ + int i; + const struct hif_msg *hif = (const struct hif_msg *)skb->data; + int hif_id = hif->id; + + if (hif_id == HIF_IND_ID_RX) { + // hif_receive_indication take care of skb lifetime + hif_receive_indication(wdev, hif, hif->body, skb); + return; + } + // Note: mutex_is_lock cause an implicit memory barrier that protect + // buf_send + if (mutex_is_locked(&wdev->hif_cmd.lock) + && wdev->hif_cmd.buf_send + && wdev->hif_cmd.buf_send->id == hif_id) { + hif_generic_confirm(wdev, hif, hif->body); + goto free; + } + for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) { + if (hif_handlers[i].msg_id == hif_id) { + if (hif_handlers[i].handler) + hif_handlers[i].handler(wdev, hif, hif->body); + goto free; + } + } + if (hif_id & 0x80) + dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n", + hif_id); + else + dev_err(wdev->dev, "unexpected HIF confirmation: ID %02x\n", + hif_id); +free: + dev_kfree_skb(skb); +} diff --git a/drivers/net/wireless/silabs/wfx/hif_rx.h b/drivers/net/wireless/silabs/wfx/hif_rx.h new file mode 100644 index 000000000000..f07c10c8c6bd --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/hif_rx.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac + * (WSM) API. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + * Copyright (C) 2010, ST-Ericsson SA + */ +#ifndef WFX_HIF_RX_H +#define WFX_HIF_RX_H + +struct wfx_dev; +struct sk_buff; + +void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb); + +#endif -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:59 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:59 +0100 Subject: [PATCH v3 16/24] wfx: add data_rx.c/data_rx.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-17-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/data_rx.c | 93 +++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/data_rx.h | 18 +++++ 2 files changed, 111 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.c create mode 100644 drivers/net/wireless/silabs/wfx/data_rx.h diff --git a/drivers/net/wireless/silabs/wfx/data_rx.c b/drivers/net/wireless/silabs/wfx/data_rx.c new file mode 100644 index 000000000000..385f2d42a0e2 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_rx.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "data_rx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" + +static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt) +{ + int params, tid; + + if (wfx_api_older_than(wvif->wdev, 3, 6)) + return; + + switch (mgmt->u.action.u.addba_req.action_code) { + case WLAN_ACTION_ADDBA_REQ: + params = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); + break; + case WLAN_ACTION_DELBA: + params = le16_to_cpu(mgmt->u.action.u.delba.params); + tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; + ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); + break; + } +} + +void wfx_rx_cb(struct wfx_vif *wvif, + const struct hif_ind_rx *arg, struct sk_buff *skb) +{ + struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); + struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + + memset(hdr, 0, sizeof(*hdr)); + + if (arg->status == HIF_STATUS_RX_FAIL_MIC) + hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED; + else if (arg->status) + goto drop; + + if (skb->len < sizeof(struct ieee80211_pspoll)) { + dev_warn(wvif->wdev->dev, "malformed SDU received\n"); + goto drop; + } + + hdr->band = NL80211_BAND_2GHZ; + hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, + hdr->band); + + if (arg->rxed_rate >= 14) { + hdr->encoding = RX_ENC_HT; + hdr->rate_idx = arg->rxed_rate - 14; + } else if (arg->rxed_rate >= 4) { + hdr->rate_idx = arg->rxed_rate - 2; + } else { + hdr->rate_idx = arg->rxed_rate; + } + + if (!arg->rcpi_rssi) { + hdr->flag |= RX_FLAG_NO_SIGNAL_VAL; + dev_info(wvif->wdev->dev, "received frame without RSSI data\n"); + } + hdr->signal = arg->rcpi_rssi / 2 - 110; + hdr->antenna = 0; + + if (arg->encryp) + hdr->flag |= RX_FLAG_DECRYPTED; + + // Block ack negotiation is offloaded by the firmware. However, + // re-ordering must be done by the mac80211. + if (ieee80211_is_action(frame->frame_control) && + mgmt->u.action.category == WLAN_CATEGORY_BACK && + skb->len > IEEE80211_MIN_ACTION_SIZE) { + wfx_rx_handle_ba(wvif, mgmt); + goto drop; + } + + ieee80211_rx_irqsafe(wvif->wdev->hw, skb); + return; + +drop: + dev_kfree_skb(skb); +} diff --git a/drivers/net/wireless/silabs/wfx/data_rx.h b/drivers/net/wireless/silabs/wfx/data_rx.h new file mode 100644 index 000000000000..4c0da37f2084 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_rx.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_RX_H +#define WFX_DATA_RX_H + +struct wfx_vif; +struct sk_buff; +struct hif_ind_rx; + +void wfx_rx_cb(struct wfx_vif *wvif, + const struct hif_ind_rx *arg, struct sk_buff *skb); + +#endif /* WFX_DATA_RX_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:00 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:00 +0100 Subject: [PATCH v3 17/24] wfx: add queue.c/queue.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-18-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/queue.c | 304 ++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/queue.h | 45 ++++ 2 files changed, 349 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/queue.c create mode 100644 drivers/net/wireless/silabs/wfx/queue.h diff --git a/drivers/net/wireless/silabs/wfx/queue.c b/drivers/net/wireless/silabs/wfx/queue.c new file mode 100644 index 000000000000..31c37f69c295 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/queue.c @@ -0,0 +1,304 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * O(1) TX queue with built-in allocator. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "queue.h" +#include "wfx.h" +#include "sta.h" +#include "data_tx.h" +#include "traces.h" + +void wfx_tx_lock(struct wfx_dev *wdev) +{ + atomic_inc(&wdev->tx_lock); +} + +void wfx_tx_unlock(struct wfx_dev *wdev) +{ + int tx_lock = atomic_dec_return(&wdev->tx_lock); + + WARN(tx_lock < 0, "inconsistent tx_lock value"); + if (!tx_lock) + wfx_bh_request_tx(wdev); +} + +void wfx_tx_flush(struct wfx_dev *wdev) +{ + int ret; + + // Do not wait for any reply if chip is frozen + if (wdev->chip_frozen) + return; + + wfx_tx_lock(wdev); + mutex_lock(&wdev->hif_cmd.lock); + ret = wait_event_timeout(wdev->hif.tx_buffers_empty, + !wdev->hif.tx_buffers_used, + msecs_to_jiffies(3000)); + if (!ret) { + dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n", + wdev->hif.tx_buffers_used); + wfx_pending_dump_old_frames(wdev, 3000); + // FIXME: drop pending frames here + wdev->chip_frozen = true; + } + mutex_unlock(&wdev->hif_cmd.lock); + wfx_tx_unlock(wdev); +} + +void wfx_tx_lock_flush(struct wfx_dev *wdev) +{ + wfx_tx_lock(wdev); + wfx_tx_flush(wdev); +} + +void wfx_tx_queues_init(struct wfx_vif *wvif) +{ + // The device is in charge to respect the details of the QoS parameters. + // The driver just ensure that it roughtly respect the priorities to + // avoid any shortage. + const int priorities[IEEE80211_NUM_ACS] = { 1, 2, 64, 128 }; + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + skb_queue_head_init(&wvif->tx_queue[i].normal); + skb_queue_head_init(&wvif->tx_queue[i].cab); + wvif->tx_queue[i].priority = priorities[i]; + } +} + +void wfx_tx_queues_check_empty(struct wfx_vif *wvif) +{ + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; ++i) { + WARN_ON(atomic_read(&wvif->tx_queue[i].pending_frames)); + WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].normal)); + WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)); + } +} + +bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue) +{ + return skb_queue_empty(&queue->normal) && skb_queue_empty(&queue->cab); +} + +static void __wfx_tx_queue_drop(struct wfx_vif *wvif, + struct sk_buff_head *skb_queue, + struct sk_buff_head *dropped) +{ + struct sk_buff *skb, *tmp; + + spin_lock_bh(&skb_queue->lock); + skb_queue_walk_safe(skb_queue, skb, tmp) { + __skb_unlink(skb, skb_queue); + skb_queue_head(dropped, skb); + } + spin_unlock_bh(&skb_queue->lock); +} + +void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, + struct sk_buff_head *dropped) +{ + __wfx_tx_queue_drop(wvif, &queue->cab, dropped); + __wfx_tx_queue_drop(wvif, &queue->normal, dropped); + wake_up(&wvif->wdev->tx_dequeue); +} + +void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb) +{ + struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + skb_queue_tail(&queue->cab, skb); + else + skb_queue_tail(&queue->normal, skb); +} + +void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped) +{ + struct wfx_queue *queue; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + + WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device", + __func__); + while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) { + hif = (struct hif_msg *)skb->data; + wvif = wdev_to_wvif(wdev, hif->interface); + if (wvif) { + queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; + WARN_ON(skb_get_queue_mapping(skb) > 3); + WARN_ON(!atomic_read(&queue->pending_frames)); + atomic_dec(&queue->pending_frames); + } + skb_queue_head(dropped, skb); + } +} + +struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id) +{ + struct wfx_queue *queue; + struct hif_req_tx *req; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + + spin_lock_bh(&wdev->tx_pending.lock); + skb_queue_walk(&wdev->tx_pending, skb) { + hif = (struct hif_msg *)skb->data; + req = (struct hif_req_tx *)hif->body; + if (req->packet_id != packet_id) + continue; + spin_unlock_bh(&wdev->tx_pending.lock); + wvif = wdev_to_wvif(wdev, hif->interface); + if (wvif) { + queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; + WARN_ON(skb_get_queue_mapping(skb) > 3); + WARN_ON(!atomic_read(&queue->pending_frames)); + atomic_dec(&queue->pending_frames); + } + skb_unlink(skb, &wdev->tx_pending); + return skb; + } + spin_unlock_bh(&wdev->tx_pending.lock); + WARN(1, "cannot find packet in pending queue"); + return NULL; +} + +void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) +{ + ktime_t now = ktime_get(); + struct wfx_tx_priv *tx_priv; + struct hif_req_tx *req; + struct sk_buff *skb; + bool first = true; + + spin_lock_bh(&wdev->tx_pending.lock); + skb_queue_walk(&wdev->tx_pending, skb) { + tx_priv = wfx_skb_tx_priv(skb); + req = wfx_skb_txreq(skb); + if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, + limit_ms))) { + if (first) { + dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n", + limit_ms); + first = false; + } + dev_info(wdev->dev, " id %08x sent %lldms ago\n", + req->packet_id, + ktime_ms_delta(now, tx_priv->xmit_timestamp)); + } + } + spin_unlock_bh(&wdev->tx_pending.lock); +} + +unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, + struct sk_buff *skb) +{ + ktime_t now = ktime_get(); + struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); + + return ktime_us_delta(now, tx_priv->xmit_timestamp); +} + +bool wfx_tx_queues_has_cab(struct wfx_vif *wvif) +{ + int i; + + if (wvif->vif->type != NL80211_IFTYPE_AP) + return false; + for (i = 0; i < IEEE80211_NUM_ACS; ++i) + // Note: since only AP can have mcast frames in queue and only + // one vif can be AP, all queued frames has same interface id + if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)) + return true; + return false; +} + +static int wfx_tx_queue_get_weight(struct wfx_queue *queue) +{ + return atomic_read(&queue->pending_frames) * queue->priority; +} + +static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev) +{ + struct wfx_queue *queues[IEEE80211_NUM_ACS * ARRAY_SIZE(wdev->vif)]; + int i, j, num_queues = 0; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + + // sort the queues + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + WARN_ON(num_queues >= ARRAY_SIZE(queues)); + queues[num_queues] = &wvif->tx_queue[i]; + for (j = num_queues; j > 0; j--) + if (wfx_tx_queue_get_weight(queues[j]) < + wfx_tx_queue_get_weight(queues[j - 1])) + swap(queues[j - 1], queues[j]); + num_queues++; + } + } + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + if (!wvif->after_dtim_tx_allowed) + continue; + for (i = 0; i < num_queues; i++) { + skb = skb_dequeue(&queues[i]->cab); + if (!skb) + continue; + // Note: since only AP can have mcast frames in queue + // and only one vif can be AP, all queued frames has + // same interface id + hif = (struct hif_msg *)skb->data; + WARN_ON(hif->interface != wvif->id); + WARN_ON(queues[i] != + &wvif->tx_queue[skb_get_queue_mapping(skb)]); + atomic_inc(&queues[i]->pending_frames); + trace_queues_stats(wdev, queues[i]); + return skb; + } + // No more multicast to sent + wvif->after_dtim_tx_allowed = false; + schedule_work(&wvif->update_tim_work); + } + + for (i = 0; i < num_queues; i++) { + skb = skb_dequeue(&queues[i]->normal); + if (skb) { + atomic_inc(&queues[i]->pending_frames); + trace_queues_stats(wdev, queues[i]); + return skb; + } + } + return NULL; +} + +struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) +{ + struct wfx_tx_priv *tx_priv; + struct sk_buff *skb; + + if (atomic_read(&wdev->tx_lock)) + return NULL; + skb = wfx_tx_queues_get_skb(wdev); + if (!skb) + return NULL; + skb_queue_tail(&wdev->tx_pending, skb); + wake_up(&wdev->tx_dequeue); + tx_priv = wfx_skb_tx_priv(skb); + tx_priv->xmit_timestamp = ktime_get(); + return (struct hif_msg *)skb->data; +} diff --git a/drivers/net/wireless/silabs/wfx/queue.h b/drivers/net/wireless/silabs/wfx/queue.h new file mode 100644 index 000000000000..80ba19455ef3 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/queue.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * O(1) TX queue with built-in allocator. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_QUEUE_H +#define WFX_QUEUE_H + +#include +#include + +struct wfx_dev; +struct wfx_vif; + +struct wfx_queue { + struct sk_buff_head normal; + struct sk_buff_head cab; // Content After (DTIM) Beacon + atomic_t pending_frames; + int priority; +}; + +void wfx_tx_lock(struct wfx_dev *wdev); +void wfx_tx_unlock(struct wfx_dev *wdev); +void wfx_tx_flush(struct wfx_dev *wdev); +void wfx_tx_lock_flush(struct wfx_dev *wdev); + +void wfx_tx_queues_init(struct wfx_vif *wvif); +void wfx_tx_queues_check_empty(struct wfx_vif *wvif); +bool wfx_tx_queues_has_cab(struct wfx_vif *wvif); +void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb); +struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev); + +bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue); +void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, + struct sk_buff_head *dropped); + +struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id); +void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped); +unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, + struct sk_buff *skb); +void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms); + +#endif /* WFX_QUEUE_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:01 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:01 +0100 Subject: [PATCH v3 18/24] wfx: add data_tx.c/data_tx.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-19-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/data_tx.c | 585 ++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/data_tx.h | 67 +++ 2 files changed, 652 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.c create mode 100644 drivers/net/wireless/silabs/wfx/data_tx.h diff --git a/drivers/net/wireless/silabs/wfx/data_tx.c b/drivers/net/wireless/silabs/wfx/data_tx.c new file mode 100644 index 000000000000..2f49da7cd538 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_tx.c @@ -0,0 +1,585 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "data_tx.h" +#include "wfx.h" +#include "bh.h" +#include "sta.h" +#include "queue.h" +#include "debug.h" +#include "traces.h" +#include "hif_tx_mib.h" + +static int wfx_get_hw_rate(struct wfx_dev *wdev, + const struct ieee80211_tx_rate *rate) +{ + struct ieee80211_supported_band *band; + + if (rate->idx < 0) + return -1; + if (rate->flags & IEEE80211_TX_RC_MCS) { + if (rate->idx > 7) { + WARN(1, "wrong rate->idx value: %d", rate->idx); + return -1; + } + return rate->idx + 14; + } + // WFx only support 2GHz, else band information should be retrieved + // from ieee80211_tx_info + band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + if (rate->idx >= band->n_bitrates) { + WARN(1, "wrong rate->idx value: %d", rate->idx); + return -1; + } + return band->bitrates[rate->idx].hw_value; +} + +/* TX policy cache implementation */ + +static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, + struct ieee80211_tx_rate *rates) +{ + struct wfx_dev *wdev = wvif->wdev; + int i, rateid; + u8 count; + + WARN(rates[0].idx < 0, "invalid rate policy"); + memset(policy, 0, sizeof(*policy)); + for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { + if (rates[i].idx < 0) + break; + WARN_ON(rates[i].count > 15); + rateid = wfx_get_hw_rate(wdev, &rates[i]); + // Pack two values in each byte of policy->rates + count = rates[i].count; + if (rateid % 2) + count <<= 4; + policy->rates[rateid / 2] |= count; + } +} + +static bool tx_policy_is_equal(const struct tx_policy *a, + const struct tx_policy *b) +{ + return !memcmp(a->rates, b->rates, sizeof(a->rates)); +} + +static int wfx_tx_policy_find(struct tx_policy_cache *cache, + struct tx_policy *wanted) +{ + struct tx_policy *it; + + list_for_each_entry(it, &cache->used, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + list_for_each_entry(it, &cache->free, link) + if (tx_policy_is_equal(wanted, it)) + return it - cache->cache; + return -1; +} + +static void wfx_tx_policy_use(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + ++entry->usage_count; + list_move(&entry->link, &cache->used); +} + +static int wfx_tx_policy_release(struct tx_policy_cache *cache, + struct tx_policy *entry) +{ + int ret = --entry->usage_count; + + if (!ret) + list_move(&entry->link, &cache->free); + return ret; +} + +static int wfx_tx_policy_get(struct wfx_vif *wvif, + struct ieee80211_tx_rate *rates, bool *renew) +{ + int idx; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + struct tx_policy wanted; + + wfx_tx_policy_build(wvif, &wanted, rates); + + spin_lock_bh(&cache->lock); + if (list_empty(&cache->free)) { + WARN(1, "unable to get a valid Tx policy"); + spin_unlock_bh(&cache->lock); + return HIF_TX_RETRY_POLICY_INVALID; + } + idx = wfx_tx_policy_find(cache, &wanted); + if (idx >= 0) { + *renew = false; + } else { + struct tx_policy *entry; + *renew = true; + /* If policy is not found create a new one + * using the oldest entry in "free" list + */ + entry = list_entry(cache->free.prev, struct tx_policy, link); + memcpy(entry->rates, wanted.rates, sizeof(entry->rates)); + entry->uploaded = false; + entry->usage_count = 0; + idx = entry - cache->cache; + } + wfx_tx_policy_use(cache, &cache->cache[idx]); + if (list_empty(&cache->free)) + ieee80211_stop_queues(wvif->wdev->hw); + spin_unlock_bh(&cache->lock); + return idx; +} + +static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) +{ + int usage, locked; + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + + if (idx == HIF_TX_RETRY_POLICY_INVALID) + return; + spin_lock_bh(&cache->lock); + locked = list_empty(&cache->free); + usage = wfx_tx_policy_release(cache, &cache->cache[idx]); + if (locked && !usage) + ieee80211_wake_queues(wvif->wdev->hw); + spin_unlock_bh(&cache->lock); +} + +static int wfx_tx_policy_upload(struct wfx_vif *wvif) +{ + struct tx_policy *policies = wvif->tx_policy_cache.cache; + u8 tmp_rates[12]; + int i, is_used; + + do { + spin_lock_bh(&wvif->tx_policy_cache.lock); + for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) { + is_used = memzcmp(policies[i].rates, + sizeof(policies[i].rates)); + if (!policies[i].uploaded && is_used) + break; + } + if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) { + policies[i].uploaded = true; + memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates)); + spin_unlock_bh(&wvif->tx_policy_cache.lock); + hif_set_tx_rate_retry_policy(wvif, i, tmp_rates); + } else { + spin_unlock_bh(&wvif->tx_policy_cache.lock); + } + } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)); + return 0; +} + +void wfx_tx_policy_upload_work(struct work_struct *work) +{ + struct wfx_vif *wvif = + container_of(work, struct wfx_vif, tx_policy_upload_work); + + wfx_tx_policy_upload(wvif); + wfx_tx_unlock(wvif->wdev); +} + +void wfx_tx_policy_init(struct wfx_vif *wvif) +{ + struct tx_policy_cache *cache = &wvif->tx_policy_cache; + int i; + + memset(cache, 0, sizeof(*cache)); + + spin_lock_init(&cache->lock); + INIT_LIST_HEAD(&cache->used); + INIT_LIST_HEAD(&cache->free); + + for (i = 0; i < ARRAY_SIZE(cache->cache); ++i) + list_add(&cache->cache[i].link, &cache->free); +} + +/* Tx implementation */ + +static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr) +{ + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + if (mgmt->u.action.category != WLAN_CATEGORY_BACK) + return false; + return true; +} + +static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct ieee80211_hdr *hdr) +{ + struct wfx_sta_priv *sta_priv = + sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL; + const u8 *da = ieee80211_get_DA(hdr); + + if (sta_priv && sta_priv->link_id) + return sta_priv->link_id; + if (wvif->vif->type != NL80211_IFTYPE_AP) + return 0; + if (is_multicast_ether_addr(da)) + return 0; + return HIF_LINK_ID_NOT_ASSOCIATED; +} + +static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) +{ + int i; + bool finished; + + // Firmware is not able to mix rates with different flags + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; + if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) + rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + } + + // Sort rates and remove duplicates + do { + finished = true; + for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { + if (rates[i + 1].idx == rates[i].idx && + rates[i].idx != -1) { + rates[i].count += rates[i + 1].count; + if (rates[i].count > 15) + rates[i].count = 15; + rates[i + 1].idx = -1; + rates[i + 1].count = 0; + + finished = false; + } + if (rates[i + 1].idx > rates[i].idx) { + swap(rates[i + 1], rates[i]); + finished = false; + } + } + } while (!finished); + // Ensure that MCS0 or 1Mbps is present at the end of the retry list + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (rates[i].idx == 0) + break; + if (rates[i].idx == -1) { + rates[i].idx = 0; + rates[i].count = 8; // == hw->max_rate_tries + rates[i].flags = rates[i - 1].flags & + IEEE80211_TX_RC_MCS; + break; + } + } + // All retries use long GI + for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) + rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; +} + +static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif, + struct ieee80211_tx_info *tx_info) +{ + bool tx_policy_renew = false; + u8 rate_id; + + rate_id = wfx_tx_policy_get(wvif, + tx_info->driver_rates, &tx_policy_renew); + if (rate_id == HIF_TX_RETRY_POLICY_INVALID) + dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy"); + + if (tx_policy_renew) { + wfx_tx_lock(wvif->wdev); + if (!schedule_work(&wvif->tx_policy_upload_work)) + wfx_tx_unlock(wvif->wdev); + } + return rate_id; +} + +static int wfx_tx_get_frame_format(struct ieee80211_tx_info *tx_info) +{ + if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_MCS)) + return HIF_FRAME_FORMAT_NON_HT; + else if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) + return HIF_FRAME_FORMAT_MIXED_FORMAT_HT; + else + return HIF_FRAME_FORMAT_GF_HT_11N; +} + +static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key) +{ + int mic_space; + + if (!hw_key) + return 0; + if (hw_key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) + return 0; + mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0; + return hw_key->icv_len + mic_space; +} + +static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, + struct sk_buff *skb) +{ + struct hif_msg *hif_msg; + struct hif_req_tx *req; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + int queue_id = skb_get_queue_mapping(skb); + size_t offset = (size_t)skb->data & 3; + int wmsg_len = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + offset; + + WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id"); + wfx_tx_fixup_rates(tx_info->driver_rates); + + // From now tx_info->control is unusable + memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); + + // Fill hif_msg + WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); + WARN(offset & 1, "attempt to transmit an unaligned frame"); + skb_put(skb, wfx_tx_get_icv_len(hw_key)); + skb_push(skb, wmsg_len); + memset(skb->data, 0, wmsg_len); + hif_msg = (struct hif_msg *)skb->data; + hif_msg->len = cpu_to_le16(skb->len); + hif_msg->id = HIF_REQ_ID_TX; + hif_msg->interface = wvif->id; + if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { + dev_warn(wvif->wdev->dev, + "requested frame size (%d) is larger than maximum supported (%d)\n", + skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); + skb_pull(skb, wmsg_len); + return -EIO; + } + + // Fill tx request + req = (struct hif_req_tx *)hif_msg->body; + // packet_id just need to be unique on device. 32bits are more than + // necessary for that task, so we tae advantage of it to add some extra + // data for debug. + req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF; + req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16; + req->packet_id |= queue_id << 28; + + req->fc_offset = offset; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + req->after_dtim = 1; + req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); + // Queue index are inverted between firmware and Linux + req->queue_id = 3 - queue_id; + req->retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info); + req->frame_format = wfx_tx_get_frame_format(tx_info); + if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + req->short_gi = 1; + + // Auxiliary operations + wfx_tx_queues_put(wvif, skb); + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + schedule_work(&wvif->update_tim_work); + wfx_bh_request_tx(wvif->wdev); + return 0; +} + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif; + struct ieee80211_sta *sta = control ? control->sta : NULL; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + size_t driver_data_room = sizeof_field(struct ieee80211_tx_info, + rate_driver_data); + + compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room, + "struct tx_priv is too large"); + WARN(skb->next || skb->prev, "skb is already member of a list"); + // control.vif can be NULL for injected frames + if (tx_info->control.vif) + wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv; + else + wvif = wvif_iterate(wdev, NULL); + if (WARN_ON(!wvif)) + goto drop; + // Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any + // BlockAck session management frame. The check below exist just in case. + if (ieee80211_is_action_back(hdr)) { + dev_info(wdev->dev, "drop BA action\n"); + goto drop; + } + if (wfx_tx_inner(wvif, sta, skb)) + goto drop; + + return; + +drop: + ieee80211_tx_status_irqsafe(wdev->hw, skb); +} + +static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + unsigned int offset = sizeof(struct hif_msg) + + sizeof(struct hif_req_tx) + + req->fc_offset; + + if (!wvif) { + pr_warn("vif associated with the skb does not exist anymore\n"); + return; + } + wfx_tx_policy_put(wvif, req->retry_policy_index); + skb_pull(skb, offset); + ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb); +} + +static void wfx_tx_fill_rates(struct wfx_dev *wdev, + struct ieee80211_tx_info *tx_info, + const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_rate *rate; + int tx_count; + int i; + + tx_count = arg->ack_failures; + if (!arg->status || arg->ack_failures) + tx_count += 1; // Also report success + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + rate = &tx_info->status.rates[i]; + if (rate->idx < 0) + break; + if (tx_count < rate->count && + arg->status == HIF_STATUS_TX_FAIL_RETRIES && + arg->ack_failures) + dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n", + rate->count, tx_count); + if (tx_count <= rate->count && tx_count && + arg->txed_rate != wfx_get_hw_rate(wdev, rate)) + dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n", + arg->txed_rate, wfx_get_hw_rate(wdev, rate)); + if (tx_count > rate->count) { + tx_count -= rate->count; + } else if (!tx_count) { + rate->count = 0; + rate->idx = -1; + } else { + rate->count = tx_count; + tx_count = 0; + } + } + if (tx_count) + dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count); +} + +void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg) +{ + struct ieee80211_tx_info *tx_info; + struct wfx_vif *wvif; + struct sk_buff *skb; + + skb = wfx_pending_get(wdev, arg->packet_id); + if (!skb) { + dev_warn(wdev->dev, "received unknown packet_id (%#.8x) from chip\n", + arg->packet_id); + return; + } + tx_info = IEEE80211_SKB_CB(skb); + wvif = wdev_to_wvif(wdev, ((struct hif_msg *)skb->data)->interface); + WARN_ON(!wvif); + if (!wvif) + return; + + // Note that wfx_pending_get_pkt_us_delay() get data from tx_info + _trace_tx_stats(arg, skb, wfx_pending_get_pkt_us_delay(wdev, skb)); + wfx_tx_fill_rates(wdev, tx_info, arg); + // From now, you can touch to tx_info->status, but do not touch to + // tx_priv anymore + // FIXME: use ieee80211_tx_info_clear_status() + memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data)); + memset(tx_info->pad, 0, sizeof(tx_info->pad)); + + if (!arg->status) { + tx_info->status.tx_time = + le32_to_cpu(arg->media_delay) - + le32_to_cpu(arg->tx_queue_delay); + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) { + WARN(!arg->requeue, "incoherent status and result_flags"); + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + wvif->after_dtim_tx_allowed = false; // DTIM period elapsed + schedule_work(&wvif->update_tim_work); + } + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + } + wfx_skb_dtor(wvif, skb); +} + +static void wfx_flush_vif(struct wfx_vif *wvif, u32 queues, + struct sk_buff_head *dropped) +{ + struct wfx_queue *queue; + int i; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wvif->tx_queue[i]; + if (dropped) + wfx_tx_queue_drop(wvif, queue, dropped); + } + if (wvif->wdev->chip_frozen) + return; + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (!(BIT(i) & queues)) + continue; + queue = &wvif->tx_queue[i]; + if (wait_event_timeout(wvif->wdev->tx_dequeue, + wfx_tx_queue_empty(wvif, queue), + msecs_to_jiffies(1000)) <= 0) + dev_warn(wvif->wdev->dev, + "frames queued while flushing tx queues?"); + } +} + +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct wfx_dev *wdev = hw->priv; + struct sk_buff_head dropped; + struct wfx_vif *wvif; + struct hif_msg *hif; + struct sk_buff *skb; + + skb_queue_head_init(&dropped); + if (vif) { + wvif = (struct wfx_vif *)vif->drv_priv; + wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); + } else { + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); + } + wfx_tx_flush(wdev); + if (wdev->chip_frozen) + wfx_pending_drop(wdev, &dropped); + while ((skb = skb_dequeue(&dropped)) != NULL) { + hif = (struct hif_msg *)skb->data; + wvif = wdev_to_wvif(wdev, hif->interface); + ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); + wfx_skb_dtor(wvif, skb); + } +} diff --git a/drivers/net/wireless/silabs/wfx/data_tx.h b/drivers/net/wireless/silabs/wfx/data_tx.h new file mode 100644 index 000000000000..46c9fff7a870 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/data_tx.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Datapath implementation. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_DATA_TX_H +#define WFX_DATA_TX_H + +#include +#include + +#include "hif_api_cmd.h" +#include "hif_api_mib.h" + +struct wfx_tx_priv; +struct wfx_dev; +struct wfx_vif; + +struct tx_policy { + struct list_head link; + int usage_count; + u8 rates[12]; + bool uploaded; +}; + +struct tx_policy_cache { + struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX]; + // FIXME: use a trees and drop hash from tx_policy + struct list_head used; + struct list_head free; + spinlock_t lock; +}; + +struct wfx_tx_priv { + ktime_t xmit_timestamp; +}; + +void wfx_tx_policy_init(struct wfx_vif *wvif); +void wfx_tx_policy_upload_work(struct work_struct *work); + +void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, + struct sk_buff *skb); +void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg); +void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); + +static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) +{ + struct ieee80211_tx_info *tx_info; + + if (!skb) + return NULL; + tx_info = IEEE80211_SKB_CB(skb); + return (struct wfx_tx_priv *)tx_info->rate_driver_data; +} + +static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb) +{ + struct hif_msg *hif = (struct hif_msg *)skb->data; + struct hif_req_tx *req = (struct hif_req_tx *)hif->body; + + return req; +} + +#endif /* WFX_DATA_TX_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:07 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:07 +0100 Subject: [PATCH v3 24/24] wfx: get out from the staging area In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-25-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller The wfx driver is now mature enough to leave the staging area. Signed-off-by: J?r?me Pouiller --- MAINTAINERS | 3 ++- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/Makefile | 1 + drivers/net/wireless/silabs/Kconfig | 18 ++++++++++++++++++ drivers/net/wireless/silabs/Makefile | 3 +++ drivers/staging/Kconfig | 2 -- drivers/staging/Makefile | 1 - drivers/staging/wfx/TODO | 6 ------ 8 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 drivers/net/wireless/silabs/Kconfig create mode 100644 drivers/net/wireless/silabs/Makefile delete mode 100644 drivers/staging/wfx/TODO diff --git a/MAINTAINERS b/MAINTAINERS index 6d4b80de1406..4bf9c4170d33 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15946,7 +15946,8 @@ F: drivers/platform/x86/touchscreen_dmi.c SILICON LABS WIRELESS DRIVERS (for WFxxx series) M: J?r?me Pouiller S: Supported -F: drivers/staging/wfx/ +F: Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml +F: drivers/net/wireless/silabs/wfx/ SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 170a64e67709..69ea83279907 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -44,6 +44,7 @@ source "drivers/net/wireless/microchip/Kconfig" source "drivers/net/wireless/ralink/Kconfig" source "drivers/net/wireless/realtek/Kconfig" source "drivers/net/wireless/rsi/Kconfig" +source "drivers/net/wireless/silabs/Kconfig" source "drivers/net/wireless/st/Kconfig" source "drivers/net/wireless/ti/Kconfig" source "drivers/net/wireless/zydas/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 80b324499786..76885e5f0ea7 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_WLAN_VENDOR_MICROCHIP) += microchip/ obj-$(CONFIG_WLAN_VENDOR_RALINK) += ralink/ obj-$(CONFIG_WLAN_VENDOR_REALTEK) += realtek/ obj-$(CONFIG_WLAN_VENDOR_RSI) += rsi/ +obj-$(CONFIG_WLAN_VENDOR_SILABS) += silabs/ obj-$(CONFIG_WLAN_VENDOR_ST) += st/ obj-$(CONFIG_WLAN_VENDOR_TI) += ti/ obj-$(CONFIG_WLAN_VENDOR_ZYDAS) += zydas/ diff --git a/drivers/net/wireless/silabs/Kconfig b/drivers/net/wireless/silabs/Kconfig new file mode 100644 index 000000000000..6262a799bf36 --- /dev/null +++ b/drivers/net/wireless/silabs/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0 + +config WLAN_VENDOR_SILABS + bool "Silicon Laboratories devices" + default y + help + If you have a wireless card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all the + questions about these cards. If you say Y, you will be asked for + your specific card in the following questions. + +if WLAN_VENDOR_SILABS + +source "drivers/net/wireless/silabs/wfx/Kconfig" + +endif # WLAN_VENDOR_SILABS diff --git a/drivers/net/wireless/silabs/Makefile b/drivers/net/wireless/silabs/Makefile new file mode 100644 index 000000000000..c2263ee21006 --- /dev/null +++ b/drivers/net/wireless/silabs/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_WFX) += wfx/ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 443ca3f3cdf0..436363affea9 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -116,8 +116,6 @@ source "drivers/staging/qlge/Kconfig" source "drivers/staging/wimax/Kconfig" -source "drivers/staging/wfx/Kconfig" - source "drivers/staging/hikey9xx/Kconfig" endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index dc45128ef525..cbfd0524755a 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -48,5 +48,4 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ obj-$(CONFIG_KPC2000) += kpc2000/ obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_WIMAX) += wimax/ -obj-$(CONFIG_WFX) += wfx/ obj-y += hikey9xx/ diff --git a/drivers/staging/wfx/TODO b/drivers/staging/wfx/TODO deleted file mode 100644 index 1b4bc2af94b6..000000000000 --- a/drivers/staging/wfx/TODO +++ /dev/null @@ -1,6 +0,0 @@ -This is a list of things that need to be done to get this driver out of the -staging directory. - - - As suggested by Felix, rate control could be improved following this idea: - https://lore.kernel.org/lkml/3099559.gv3Q75KnN1 at pc-42/ - -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:04 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:04 +0100 Subject: [PATCH v3 21/24] wfx: add debug.c/debug.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-22-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/debug.c | 359 ++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/debug.h | 19 ++ 2 files changed, 378 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/debug.c create mode 100644 drivers/net/wireless/silabs/wfx/debug.h diff --git a/drivers/net/wireless/silabs/wfx/debug.c b/drivers/net/wireless/silabs/wfx/debug.c new file mode 100644 index 000000000000..eedada78c25f --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/debug.c @@ -0,0 +1,359 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Debugfs interface. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include +#include + +#include "debug.h" +#include "wfx.h" +#include "sta.h" +#include "main.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define CREATE_TRACE_POINTS +#include "traces.h" + +static const struct trace_print_flags hif_msg_print_map[] = { + hif_msg_list, +}; + +static const struct trace_print_flags hif_mib_print_map[] = { + hif_mib_list, +}; + +static const struct trace_print_flags wfx_reg_print_map[] = { + wfx_reg_list, +}; + +static const char *get_symbol(unsigned long val, + const struct trace_print_flags *symbol_array) +{ + int i; + + for (i = 0; symbol_array[i].mask != -1; i++) { + if (val == symbol_array[i].mask) + return symbol_array[i].name; + } + + return "unknown"; +} + +const char *get_hif_name(unsigned long id) +{ + return get_symbol(id, hif_msg_print_map); +} + +const char *get_mib_name(unsigned long id) +{ + return get_symbol(id, hif_mib_print_map); +} + +const char *get_reg_name(unsigned long id) +{ + return get_symbol(id, wfx_reg_print_map); +} + +static int wfx_counters_show(struct seq_file *seq, void *v) +{ + int ret, i; + struct wfx_dev *wdev = seq->private; + struct hif_mib_extended_count_table counters[3]; + + for (i = 0; i < ARRAY_SIZE(counters); i++) { + ret = hif_get_counters_table(wdev, i, counters + i); + if (ret < 0) + return ret; + if (ret > 0) + return -EIO; + } + + seq_printf(seq, "%-24s %12s %12s %12s\n", + "", "global", "iface 0", "iface 1"); + +#define PUT_COUNTER(name) \ + seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \ + le32_to_cpu(counters[2].count_##name), \ + le32_to_cpu(counters[0].count_##name), \ + le32_to_cpu(counters[1].count_##name)) + + PUT_COUNTER(tx_packets); + PUT_COUNTER(tx_multicast_frames); + PUT_COUNTER(tx_frames_success); + PUT_COUNTER(tx_frame_failures); + PUT_COUNTER(tx_frames_retried); + PUT_COUNTER(tx_frames_multi_retried); + + PUT_COUNTER(rts_success); + PUT_COUNTER(rts_failures); + PUT_COUNTER(ack_failures); + + PUT_COUNTER(rx_packets); + PUT_COUNTER(rx_frames_success); + PUT_COUNTER(rx_packet_errors); + PUT_COUNTER(plcp_errors); + PUT_COUNTER(fcs_errors); + PUT_COUNTER(rx_decryption_failures); + PUT_COUNTER(rx_mic_failures); + PUT_COUNTER(rx_no_key_failures); + PUT_COUNTER(rx_frame_duplicates); + PUT_COUNTER(rx_multicast_frames); + PUT_COUNTER(rx_cmacicv_errors); + PUT_COUNTER(rx_cmac_replays); + PUT_COUNTER(rx_mgmt_ccmp_replays); + + PUT_COUNTER(rx_beacon); + PUT_COUNTER(miss_beacon); + +#undef PUT_COUNTER + + for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++) + seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "", + le32_to_cpu(counters[2].reserved[i]), + le32_to_cpu(counters[0].reserved[i]), + le32_to_cpu(counters[1].reserved[i])); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_counters); + +static const char * const channel_names[] = { + [0] = "1M", + [1] = "2M", + [2] = "5.5M", + [3] = "11M", + /* Entries 4 and 5 does not exist */ + [6] = "6M", + [7] = "9M", + [8] = "12M", + [9] = "18M", + [10] = "24M", + [11] = "36M", + [12] = "48M", + [13] = "54M", + [14] = "MCS0", + [15] = "MCS1", + [16] = "MCS2", + [17] = "MCS3", + [18] = "MCS4", + [19] = "MCS5", + [20] = "MCS6", + [21] = "MCS7", +}; + +static int wfx_rx_stats_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_rx_stats *st = &wdev->rx_stats; + int i; + + mutex_lock(&wdev->rx_stats_lock); + seq_printf(seq, "Timestamp: %dus\n", st->date); + seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", + le32_to_cpu(st->pwr_clk_freq), + st->is_ext_pwr_clk ? "yes" : "no"); + seq_printf(seq, + "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", + st->nb_rx_frame, st->per_total, st->throughput); + seq_puts(seq, " Num. of PER RSSI SNR CFO\n"); + seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n"); + for (i = 0; i < ARRAY_SIZE(channel_names); i++) { + if (channel_names[i]) + seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", + channel_names[i], + le32_to_cpu(st->nb_rx_by_rate[i]), + le16_to_cpu(st->per[i]), + (s16)le16_to_cpu(st->rssi[i]) / 100, + (s16)le16_to_cpu(st->snr[i]) / 100, + (s16)le16_to_cpu(st->cfo[i])); + } + mutex_unlock(&wdev->rx_stats_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); + +static int wfx_tx_power_loop_show(struct seq_file *seq, void *v) +{ + struct wfx_dev *wdev = seq->private; + struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info; + int tmp; + + mutex_lock(&wdev->tx_power_loop_info_lock); + tmp = le16_to_cpu(st->tx_gain_dig); + seq_printf(seq, "Tx gain digital: %d\n", tmp); + tmp = le16_to_cpu(st->tx_gain_pa); + seq_printf(seq, "Tx gain PA: %d\n", tmp); + tmp = (s16)le16_to_cpu(st->target_pout); + seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = (s16)le16_to_cpu(st->p_estimation); + seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); + tmp = le16_to_cpu(st->vpdet); + seq_printf(seq, "Vpdet: %d mV\n", tmp); + seq_printf(seq, "Measure index: %d\n", st->measurement_index); + mutex_unlock(&wdev->tx_power_loop_info_lock); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop); + +static ssize_t wfx_send_pds_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wfx_dev *wdev = file->private_data; + char *buf; + int ret; + + if (*ppos != 0) { + dev_dbg(wdev->dev, "PDS data must be written in one transaction"); + return -EBUSY; + } + buf = memdup_user(user_buf, count); + if (IS_ERR(buf)) + return PTR_ERR(buf); + *ppos = *ppos + count; + ret = wfx_send_pds(wdev, buf, count); + kfree(buf); + if (ret < 0) + return ret; + return count; +} + +static const struct file_operations wfx_send_pds_fops = { + .open = simple_open, + .write = wfx_send_pds_write, +}; + +struct dbgfs_hif_msg { + struct wfx_dev *wdev; + struct completion complete; + u8 reply[1024]; + int ret; +}; + +static ssize_t wfx_send_hif_msg_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + struct wfx_dev *wdev = context->wdev; + struct hif_msg *request; + + if (completion_done(&context->complete)) { + dev_dbg(wdev->dev, "read previous result before start a new one\n"); + return -EBUSY; + } + if (count < sizeof(struct hif_msg)) + return -EINVAL; + + // wfx_cmd_send() checks that reply buffer is wide enough, but does not + // return precise length read. User have to know how many bytes should + // be read. Filling reply buffer with a memory pattern may help user. + memset(context->reply, 0xFF, sizeof(context->reply)); + request = memdup_user(user_buf, count); + if (IS_ERR(request)) + return PTR_ERR(request); + if (le16_to_cpu(request->len) != count) { + kfree(request); + return -EINVAL; + } + context->ret = wfx_cmd_send(wdev, request, context->reply, + sizeof(context->reply), false); + + kfree(request); + complete(&context->complete); + return count; +} + +static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct dbgfs_hif_msg *context = file->private_data; + int ret; + + if (count > sizeof(context->reply)) + return -EINVAL; + ret = wait_for_completion_interruptible(&context->complete); + if (ret) + return ret; + if (context->ret < 0) + return context->ret; + // Be careful, write() is waiting for a full message while read() + // only returns a payload + if (copy_to_user(user_buf, context->reply, count)) + return -EFAULT; + + return count; +} + +static int wfx_send_hif_msg_open(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL); + + if (!context) + return -ENOMEM; + context->wdev = inode->i_private; + init_completion(&context->complete); + file->private_data = context; + return 0; +} + +static int wfx_send_hif_msg_release(struct inode *inode, struct file *file) +{ + struct dbgfs_hif_msg *context = file->private_data; + + kfree(context); + return 0; +} + +static const struct file_operations wfx_send_hif_msg_fops = { + .open = wfx_send_hif_msg_open, + .release = wfx_send_hif_msg_release, + .write = wfx_send_hif_msg_write, + .read = wfx_send_hif_msg_read, +}; + +static int wfx_ps_timeout_set(void *data, u64 val) +{ + struct wfx_dev *wdev = (struct wfx_dev *)data; + struct wfx_vif *wvif; + + wdev->force_ps_timeout = val; + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); + return 0; +} + +static int wfx_ps_timeout_get(void *data, u64 *val) +{ + struct wfx_dev *wdev = (struct wfx_dev *)data; + + *val = wdev->force_ps_timeout; + return 0; +} + +DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n"); + +int wfx_debug_init(struct wfx_dev *wdev) +{ + struct dentry *d; + + d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); + debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); + debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); + debugfs_create_file("tx_power_loop", 0444, d, wdev, + &wfx_tx_power_loop_fops); + debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); + debugfs_create_file("send_hif_msg", 0600, d, wdev, + &wfx_send_hif_msg_fops); + debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops); + + return 0; +} diff --git a/drivers/net/wireless/silabs/wfx/debug.h b/drivers/net/wireless/silabs/wfx/debug.h new file mode 100644 index 000000000000..6f2f84d64c9e --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/debug.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Debugfs interface. + * + * Copyright (c) 2017-2019, Silicon Laboratories, Inc. + * Copyright (c) 2011, ST-Ericsson + */ +#ifndef WFX_DEBUG_H +#define WFX_DEBUG_H + +struct wfx_dev; + +int wfx_debug_init(struct wfx_dev *wdev); + +const char *get_hif_name(unsigned long id); +const char *get_mib_name(unsigned long id); +const char *get_reg_name(unsigned long id); + +#endif /* WFX_DEBUG_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:05 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:05 +0100 Subject: [PATCH v3 22/24] wfx: add traces.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-23-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/traces.h | 501 +++++++++++++++++++++++ 1 file changed, 501 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/traces.h diff --git a/drivers/net/wireless/silabs/wfx/traces.h b/drivers/net/wireless/silabs/wfx/traces.h new file mode 100644 index 000000000000..e34c7a538c65 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/traces.h @@ -0,0 +1,501 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Tracepoints definitions. + * + * Copyright (c) 2018-2020, Silicon Laboratories, Inc. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM wfx + +#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define _WFX_TRACE_H + +#include +#include + +#include "bus.h" +#include "hif_api_cmd.h" +#include "hif_api_mib.h" + +/* The hell below need some explanations. For each symbolic number, we need to + * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic. + * + * 1. Define a new macro that call TRACE_DEFINE_ENUM(): + * + * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym); + * + * 2. Define list of all symbols: + * + * #define list_names \ + * ... \ + * xxx_name(XXX) \ + * ... + * + * 3. Instantiate that list_names: + * + * list_names + * + * 4. Redefine xxx_name() as an entry of array for __print_symbolic() + * + * #undef xxx_name + * #define xxx_name(msg) { msg, #msg }, + * + * 5. list_name can now nearly be used with __print_symbolic() but, + * __print_symbolic() dislike last comma of list. So we define a new list + * with a dummy element: + * + * #define list_for_print_symbolic list_names { -1, NULL } + */ + +#define _hif_msg_list \ + hif_cnf_name(ADD_KEY) \ + hif_cnf_name(BEACON_TRANSMIT) \ + hif_cnf_name(EDCA_QUEUE_PARAMS) \ + hif_cnf_name(JOIN) \ + hif_cnf_name(MAP_LINK) \ + hif_cnf_name(READ_MIB) \ + hif_cnf_name(REMOVE_KEY) \ + hif_cnf_name(RESET) \ + hif_cnf_name(SET_BSS_PARAMS) \ + hif_cnf_name(SET_PM_MODE) \ + hif_cnf_name(START) \ + hif_cnf_name(START_SCAN) \ + hif_cnf_name(STOP_SCAN) \ + hif_cnf_name(TX) \ + hif_cnf_name(MULTI_TRANSMIT) \ + hif_cnf_name(UPDATE_IE) \ + hif_cnf_name(WRITE_MIB) \ + hif_cnf_name(CONFIGURATION) \ + hif_cnf_name(CONTROL_GPIO) \ + hif_cnf_name(PREVENT_ROLLBACK) \ + hif_cnf_name(SET_SL_MAC_KEY) \ + hif_cnf_name(SL_CONFIGURE) \ + hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \ + hif_cnf_name(SHUT_DOWN) \ + hif_ind_name(EVENT) \ + hif_ind_name(JOIN_COMPLETE) \ + hif_ind_name(RX) \ + hif_ind_name(SCAN_CMPL) \ + hif_ind_name(SET_PM_MODE_CMPL) \ + hif_ind_name(SUSPEND_RESUME_TX) \ + hif_ind_name(SL_EXCHANGE_PUB_KEYS) \ + hif_ind_name(ERROR) \ + hif_ind_name(EXCEPTION) \ + hif_ind_name(GENERIC) \ + hif_ind_name(WAKEUP) \ + hif_ind_name(STARTUP) + +#define hif_msg_list_enum _hif_msg_list + +#undef hif_cnf_name +#undef hif_ind_name +#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg); +#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg); +hif_msg_list_enum +#undef hif_cnf_name +#undef hif_ind_name +#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg }, +#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg }, +#define hif_msg_list hif_msg_list_enum { -1, NULL } + +#define _hif_mib_list \ + hif_mib_name(ARP_IP_ADDRESSES_TABLE) \ + hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \ + hif_mib_name(BEACON_FILTER_ENABLE) \ + hif_mib_name(BEACON_FILTER_TABLE) \ + hif_mib_name(BEACON_STATS) \ + hif_mib_name(BEACON_WAKEUP_PERIOD) \ + hif_mib_name(BLOCK_ACK_POLICY) \ + hif_mib_name(CCA_CONFIG) \ + hif_mib_name(CONFIG_DATA_FILTER) \ + hif_mib_name(COUNTERS_TABLE) \ + hif_mib_name(CURRENT_TX_POWER_LEVEL) \ + hif_mib_name(DOT11_MAC_ADDRESS) \ + hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \ + hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \ + hif_mib_name(DOT11_RTS_THRESHOLD) \ + hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \ + hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ + hif_mib_name(EXTENDED_COUNTERS_TABLE) \ + hif_mib_name(GL_BLOCK_ACK_INFO) \ + hif_mib_name(GL_OPERATIONAL_POWER_MODE) \ + hif_mib_name(GL_SET_MULTI_MSG) \ + hif_mib_name(GRP_SEQ_COUNTER) \ + hif_mib_name(INACTIVITY_TIMER) \ + hif_mib_name(INTERFACE_PROTECTION) \ + hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(KEEP_ALIVE_PERIOD) \ + hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \ + hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ + hif_mib_name(MAX_TX_POWER_LEVEL) \ + hif_mib_name(NON_ERP_PROTECTION) \ + hif_mib_name(NS_IP_ADDRESSES_TABLE) \ + hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \ + hif_mib_name(PORT_DATAFRAME_CONDITION) \ + hif_mib_name(PROTECTED_MGMT_POLICY) \ + hif_mib_name(RCPI_RSSI_THRESHOLD) \ + hif_mib_name(RX_FILTER) \ + hif_mib_name(SET_ASSOCIATION_MODE) \ + hif_mib_name(SET_DATA_FILTERING) \ + hif_mib_name(SET_HT_PROTECTION) \ + hif_mib_name(SET_TX_RATE_RETRY_POLICY) \ + hif_mib_name(SET_UAPSD_INFORMATION) \ + hif_mib_name(SLOT_TIME) \ + hif_mib_name(STATISTICS_TABLE) \ + hif_mib_name(TEMPLATE_FRAME) \ + hif_mib_name(TSF_COUNTER) \ + hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION) + +#define hif_mib_list_enum _hif_mib_list + +#undef hif_mib_name +#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib); +hif_mib_list_enum +#undef hif_mib_name +#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib }, +#define hif_mib_list hif_mib_list_enum { -1, NULL } + +DECLARE_EVENT_CLASS(hif_data, + TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv), + TP_STRUCT__entry( + __field(int, tx_fill_level) + __field(int, msg_id) + __field(const char *, msg_type) + __field(int, msg_len) + __field(int, buf_len) + __field(int, if_id) + __field(int, mib) + __array(u8, buf, 128) + ), + TP_fast_assign( + int header_len; + + __entry->tx_fill_level = tx_fill_level; + __entry->msg_len = le16_to_cpu(hif->len); + __entry->msg_id = hif->id; + __entry->if_id = hif->interface; + if (is_recv) + __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF"; + else + __entry->msg_type = "REQ"; + if (!is_recv && + (__entry->msg_id == HIF_REQ_ID_READ_MIB || + __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) { + __entry->mib = le16_to_cpup((__le16 *)hif->body); + header_len = 4; + } else { + __entry->mib = -1; + header_len = 0; + } + __entry->buf_len = min_t(int, __entry->msg_len, + sizeof(__entry->buf)) + - sizeof(struct hif_msg) - header_len; + memcpy(__entry->buf, hif->body + header_len, __entry->buf_len); + ), + TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)", + __entry->tx_fill_level, + __entry->if_id, + __entry->msg_type, + __print_symbolic(__entry->msg_id, hif_msg_list), + __entry->mib != -1 ? "/" : "", + __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "", + __print_hex(__entry->buf, __entry->buf_len), + __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", + __entry->msg_len + ) +); +DEFINE_EVENT(hif_data, hif_send, + TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv)); +#define _trace_hif_send(hif, tx_fill_level)\ + trace_hif_send(hif, tx_fill_level, false) +DEFINE_EVENT(hif_data, hif_recv, + TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), + TP_ARGS(hif, tx_fill_level, is_recv)); +#define _trace_hif_recv(hif, tx_fill_level)\ + trace_hif_recv(hif, tx_fill_level, true) + +#define wfx_reg_list_enum \ + wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \ + wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \ + wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \ + wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \ + wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \ + wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \ + wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \ + wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT") + +#undef wfx_reg_name +#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym); +wfx_reg_list_enum +#undef wfx_reg_name +#define wfx_reg_name(sym, name) { sym, name }, +#define wfx_reg_list wfx_reg_list_enum { -1, NULL } + +DECLARE_EVENT_CLASS(io_data, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len), + TP_STRUCT__entry( + __field(int, reg) + __field(int, addr) + __field(int, msg_len) + __field(int, buf_len) + __array(u8, buf, 32) + __array(u8, addr_str, 10) + ), + TP_fast_assign( + __entry->reg = reg; + __entry->addr = addr; + __entry->msg_len = len; + __entry->buf_len = min_t(int, sizeof(__entry->buf), + __entry->msg_len); + memcpy(__entry->buf, io_buf, __entry->buf_len); + if (addr >= 0) + snprintf(__entry->addr_str, 10, "/%08x", addr); + else + __entry->addr_str[0] = 0; + ), + TP_printk("%s%s: %s%s (%d bytes)", + __print_symbolic(__entry->reg, wfx_reg_list), + __entry->addr_str, + __print_hex(__entry->buf, __entry->buf_len), + __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", + __entry->msg_len + ) +); +DEFINE_EVENT(io_data, io_write, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len)); +#define _trace_io_ind_write(reg, addr, io_buf, len)\ + trace_io_write(reg, addr, io_buf, len) +#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len) +DEFINE_EVENT(io_data, io_read, + TP_PROTO(int reg, int addr, const void *io_buf, size_t len), + TP_ARGS(reg, addr, io_buf, len)); +#define _trace_io_ind_read(reg, addr, io_buf, len)\ + trace_io_read(reg, addr, io_buf, len) +#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len) + +DECLARE_EVENT_CLASS(io_data32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val), + TP_STRUCT__entry( + __field(int, reg) + __field(int, addr) + __field(int, val) + __array(u8, addr_str, 10) + ), + TP_fast_assign( + __entry->reg = reg; + __entry->addr = addr; + __entry->val = val; + if (addr >= 0) + snprintf(__entry->addr_str, 10, "/%08x", addr); + else + __entry->addr_str[0] = 0; + ), + TP_printk("%s%s: %08x", + __print_symbolic(__entry->reg, wfx_reg_list), + __entry->addr_str, + __entry->val + ) +); +DEFINE_EVENT(io_data32, io_write32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val)); +#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val) +#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val) +DEFINE_EVENT(io_data32, io_read32, + TP_PROTO(int reg, int addr, u32 val), + TP_ARGS(reg, addr, val)); +#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val) +#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val) + +DECLARE_EVENT_CLASS(piggyback, + TP_PROTO(u32 val, bool ignored), + TP_ARGS(val, ignored), + TP_STRUCT__entry( + __field(int, val) + __field(bool, ignored) + ), + TP_fast_assign( + __entry->val = val; + __entry->ignored = ignored; + ), + TP_printk("CONTROL: %08x%s", + __entry->val, + __entry->ignored ? " (ignored)" : "" + ) +); +DEFINE_EVENT(piggyback, piggyback, + TP_PROTO(u32 val, bool ignored), + TP_ARGS(val, ignored)); +#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored) + +TRACE_EVENT(bh_stats, + TP_PROTO(int ind, int req, int cnf, int busy, bool release), + TP_ARGS(ind, req, cnf, busy, release), + TP_STRUCT__entry( + __field(int, ind) + __field(int, req) + __field(int, cnf) + __field(int, busy) + __field(bool, release) + ), + TP_fast_assign( + __entry->ind = ind; + __entry->req = req; + __entry->cnf = cnf; + __entry->busy = busy; + __entry->release = release; + ), + TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s", + __entry->ind, + __entry->req, + __entry->cnf, + __entry->busy, + __entry->release ? "release" : "keep" + ) +); +#define _trace_bh_stats(ind, req, cnf, busy, release)\ + trace_bh_stats(ind, req, cnf, busy, release) + +TRACE_EVENT(tx_stats, + TP_PROTO(const struct hif_cnf_tx *tx_cnf, const struct sk_buff *skb, + int delay), + TP_ARGS(tx_cnf, skb, delay), + TP_STRUCT__entry( + __field(int, pkt_id) + __field(int, delay_media) + __field(int, delay_queue) + __field(int, delay_fw) + __field(int, ack_failures) + __field(int, flags) + __array(int, rate, 4) + __array(int, tx_count, 4) + ), + TP_fast_assign( + // Keep sync with wfx_rates definition in main.c + static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9, + 10, 11, 12, 13 }; + const struct ieee80211_tx_info *tx_info = + (const struct ieee80211_tx_info *)skb->cb; + const struct ieee80211_tx_rate *rates = tx_info->driver_rates; + int i; + + __entry->pkt_id = tx_cnf->packet_id; + __entry->delay_media = le32_to_cpu(tx_cnf->media_delay); + __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay); + __entry->delay_fw = delay; + __entry->ack_failures = tx_cnf->ack_failures; + if (!tx_cnf->status || __entry->ack_failures) + __entry->ack_failures += 1; + + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + if (rates[0].flags & IEEE80211_TX_RC_MCS) + __entry->rate[i] = rates[i].idx; + else + __entry->rate[i] = hw_rate[rates[i].idx]; + __entry->tx_count[i] = rates[i].count; + } + __entry->flags = 0; + if (rates[0].flags & IEEE80211_TX_RC_MCS) + __entry->flags |= 0x01; + if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) + __entry->flags |= 0x02; + if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) + __entry->flags |= 0x04; + if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + __entry->flags |= 0x08; + if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) + __entry->flags |= 0x10; + if (tx_cnf->status) + __entry->flags |= 0x20; + if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE) + __entry->flags |= 0x40; + ), + TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus", + __entry->pkt_id, + __print_flags(__entry->flags, NULL, + { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" }, + { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" }, + { 0x40, "Q" }), + __entry->rate[0], + __entry->tx_count[0], + __entry->rate[1], + __entry->tx_count[1], + __entry->rate[2], + __entry->tx_count[2], + __entry->rate[3], + __entry->tx_count[3], + __entry->ack_failures, + __entry->delay_media, + __entry->delay_queue, + __entry->delay_fw + ) +); +#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay) + +TRACE_EVENT(queues_stats, + TP_PROTO(struct wfx_dev *wdev, const struct wfx_queue *elected_queue), + TP_ARGS(wdev, elected_queue), + TP_STRUCT__entry( + __field(int, vif_id) + __field(int, queue_id) + __array(int, hw, IEEE80211_NUM_ACS * 2) + __array(int, drv, IEEE80211_NUM_ACS * 2) + __array(int, cab, IEEE80211_NUM_ACS * 2) + ), + TP_fast_assign( + const struct wfx_queue *queue; + struct wfx_vif *wvif; + int i, j; + + for (j = 0; j < IEEE80211_NUM_ACS * 2; j++) { + __entry->hw[j] = -1; + __entry->drv[j] = -1; + __entry->cab[j] = -1; + } + __entry->vif_id = -1; + __entry->queue_id = -1; + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + j = wvif->id * IEEE80211_NUM_ACS + i; + WARN_ON(j >= IEEE80211_NUM_ACS * 2); + queue = &wvif->tx_queue[i]; + __entry->hw[j] = atomic_read(&queue->pending_frames); + __entry->drv[j] = skb_queue_len(&queue->normal); + __entry->cab[j] = skb_queue_len(&queue->cab); + if (queue == elected_queue) { + __entry->vif_id = wvif->id; + __entry->queue_id = i; + } + } + } + ), + TP_printk("got skb from %d/%d, pend. hw/norm/cab: [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ] [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ]", + __entry->vif_id, __entry->queue_id, + __entry->hw[0], __entry->drv[0], __entry->cab[0], + __entry->hw[1], __entry->drv[1], __entry->cab[1], + __entry->hw[2], __entry->drv[2], __entry->cab[2], + __entry->hw[3], __entry->drv[3], __entry->cab[3], + __entry->hw[4], __entry->drv[4], __entry->cab[4], + __entry->hw[5], __entry->drv[5], __entry->cab[5], + __entry->hw[6], __entry->drv[6], __entry->cab[6], + __entry->hw[7], __entry->drv[7], __entry->cab[7] + ) +); + +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE traces + +#include -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:06 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:06 +0100 Subject: [PATCH v3 23/24] wfx: remove from the staging area In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-24-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- .../bindings/net/wireless/silabs,wfx.yaml | 125 --- drivers/staging/wfx/Kconfig | 8 - drivers/staging/wfx/Makefile | 25 - drivers/staging/wfx/bh.c | 333 -------- drivers/staging/wfx/bh.h | 33 - drivers/staging/wfx/bus.h | 38 - drivers/staging/wfx/bus_sdio.c | 269 ------ drivers/staging/wfx/bus_spi.c | 271 ------ drivers/staging/wfx/data_rx.c | 93 -- drivers/staging/wfx/data_rx.h | 18 - drivers/staging/wfx/data_tx.c | 585 ------------- drivers/staging/wfx/data_tx.h | 67 -- drivers/staging/wfx/debug.c | 359 -------- drivers/staging/wfx/debug.h | 19 - drivers/staging/wfx/fwio.c | 405 --------- drivers/staging/wfx/fwio.h | 15 - drivers/staging/wfx/hif_api_cmd.h | 553 ------------ drivers/staging/wfx/hif_api_general.h | 267 ------ drivers/staging/wfx/hif_api_mib.h | 343 -------- drivers/staging/wfx/hif_rx.c | 415 --------- drivers/staging/wfx/hif_rx.h | 18 - drivers/staging/wfx/hif_tx.c | 523 ------------ drivers/staging/wfx/hif_tx.h | 60 -- drivers/staging/wfx/hif_tx_mib.c | 324 ------- drivers/staging/wfx/hif_tx_mib.h | 49 -- drivers/staging/wfx/hwio.c | 352 -------- drivers/staging/wfx/hwio.h | 75 -- drivers/staging/wfx/key.c | 241 ------ drivers/staging/wfx/key.h | 20 - drivers/staging/wfx/main.c | 490 ----------- drivers/staging/wfx/main.h | 44 - drivers/staging/wfx/queue.c | 304 ------- drivers/staging/wfx/queue.h | 45 - drivers/staging/wfx/scan.c | 132 --- drivers/staging/wfx/scan.h | 22 - drivers/staging/wfx/sta.c | 807 ------------------ drivers/staging/wfx/sta.h | 73 -- drivers/staging/wfx/traces.h | 501 ----------- drivers/staging/wfx/wfx.h | 166 ---- 39 files changed, 8487 deletions(-) delete mode 100644 drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml delete mode 100644 drivers/staging/wfx/Kconfig delete mode 100644 drivers/staging/wfx/Makefile delete mode 100644 drivers/staging/wfx/bh.c delete mode 100644 drivers/staging/wfx/bh.h delete mode 100644 drivers/staging/wfx/bus.h delete mode 100644 drivers/staging/wfx/bus_sdio.c delete mode 100644 drivers/staging/wfx/bus_spi.c delete mode 100644 drivers/staging/wfx/data_rx.c delete mode 100644 drivers/staging/wfx/data_rx.h delete mode 100644 drivers/staging/wfx/data_tx.c delete mode 100644 drivers/staging/wfx/data_tx.h delete mode 100644 drivers/staging/wfx/debug.c delete mode 100644 drivers/staging/wfx/debug.h delete mode 100644 drivers/staging/wfx/fwio.c delete mode 100644 drivers/staging/wfx/fwio.h delete mode 100644 drivers/staging/wfx/hif_api_cmd.h delete mode 100644 drivers/staging/wfx/hif_api_general.h delete mode 100644 drivers/staging/wfx/hif_api_mib.h delete mode 100644 drivers/staging/wfx/hif_rx.c delete mode 100644 drivers/staging/wfx/hif_rx.h delete mode 100644 drivers/staging/wfx/hif_tx.c delete mode 100644 drivers/staging/wfx/hif_tx.h delete mode 100644 drivers/staging/wfx/hif_tx_mib.c delete mode 100644 drivers/staging/wfx/hif_tx_mib.h delete mode 100644 drivers/staging/wfx/hwio.c delete mode 100644 drivers/staging/wfx/hwio.h delete mode 100644 drivers/staging/wfx/key.c delete mode 100644 drivers/staging/wfx/key.h delete mode 100644 drivers/staging/wfx/main.c delete mode 100644 drivers/staging/wfx/main.h delete mode 100644 drivers/staging/wfx/queue.c delete mode 100644 drivers/staging/wfx/queue.h delete mode 100644 drivers/staging/wfx/scan.c delete mode 100644 drivers/staging/wfx/scan.h delete mode 100644 drivers/staging/wfx/sta.c delete mode 100644 drivers/staging/wfx/sta.h delete mode 100644 drivers/staging/wfx/traces.h delete mode 100644 drivers/staging/wfx/wfx.h diff --git a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml b/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml deleted file mode 100644 index 43b5630c0407..000000000000 --- a/drivers/staging/wfx/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -# Copyright (c) 2020, Silicon Laboratories, Inc. -%YAML 1.2 ---- - -$id: http://devicetree.org/schemas/net/wireless/silabs,wfx.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Silicon Labs WFxxx devicetree bindings - -maintainers: - - J?r?me Pouiller - -description: - The WFxxx chip series can be connected via SPI or via SDIO. - - For SDIO':' - - The driver is able to detect a WFxxx chip on SDIO bus by matching its Vendor - ID and Product ID. However, driver will only provide limited features in - this case. Thus declaring WFxxx chip in device tree is recommended (and may - become mandatory in the future). - - In addition, it is recommended to declare a mmc-pwrseq on SDIO host above - WFx. Without it, you may encounter issues with warm boot. The mmc-pwrseq - should be compatible with mmc-pwrseq-simple. Please consult - Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt for more - information. - - For SPI':' - - In add of the properties below, please consult - Documentation/devicetree/bindings/spi/spi-controller.yaml for optional SPI - related properties. - - Note that in add of the properties below, the WFx driver also supports - `mac-address` and `local-mac-address` as described in - Documentation/devicetree/bindings/net/ethernet.txt - -properties: - compatible: - const: silabs,wf200 - reg: - description: - When used on SDIO bus, must be set to 1. When used on SPI bus, it is - the chip select address of the device as defined in the SPI devices - bindings. - maxItems: 1 - spi-max-frequency: - description: (SPI only) Maximum SPI clocking speed of device in Hz. - maxItems: 1 - interrupts: - description: The interrupt line. Triggers IRQ_TYPE_LEVEL_HIGH and - IRQ_TYPE_EDGE_RISING are both supported by the chip and the driver. When - SPI is used, this property is required. When SDIO is used, the "in-band" - interrupt provided by the SDIO bus is used unless an interrupt is defined - in the Device Tree. - maxItems: 1 - reset-gpios: - description: (SPI only) Phandle of gpio that will be used to reset chip - during probe. Without this property, you may encounter issues with warm - boot. (For legacy purpose, the gpio in inverted when compatible == - "silabs,wfx-spi") - - For SDIO, the reset gpio should declared using a mmc-pwrseq. - maxItems: 1 - wakeup-gpios: - description: Phandle of gpio that will be used to wake-up chip. Without this - property, driver will disable most of power saving features. - maxItems: 1 - config-file: - description: Use an alternative file as PDS. Default is `wf200.pds`. Only - necessary for development/debug purpose. - maxItems: 1 - -required: - - compatible - - reg - -examples: - - | - #include - #include - - spi0 { - #address-cells = <1>; - #size-cells = <0>; - - wfx at 0 { - compatible = "silabs,wf200"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_irq &wfx_gpios>; - reg = <0>; - interrupts-extended = <&gpio 16 IRQ_TYPE_EDGE_RISING>; - wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; - reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - spi-max-frequency = <42000000>; - }; - }; - - - | - #include - #include - - wfx_pwrseq: wfx_pwrseq { - compatible = "mmc-pwrseq-simple"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_reset>; - reset-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; - }; - - mmc0 { - mmc-pwrseq = <&wfx_pwrseq>; - #address-cells = <1>; - #size-cells = <0>; - - mmc at 1 { - compatible = "silabs,wf200"; - pinctrl-names = "default"; - pinctrl-0 = <&wfx_wakeup>; - reg = <1>; - wakeup-gpios = <&gpio 12 GPIO_ACTIVE_HIGH>; - }; - }; -... diff --git a/drivers/staging/wfx/Kconfig b/drivers/staging/wfx/Kconfig deleted file mode 100644 index 83ee4d0ca8c6..000000000000 --- a/drivers/staging/wfx/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config WFX - tristate "Silicon Labs wireless chips WF200 and further" - depends on MAC80211 - depends on MMC || !MMC # do not allow WFX=y if MMC=m - depends on (SPI || MMC) - help - This is a driver for Silicons Labs WFxxx series (WF200 and further) - chipsets. This chip can be found on SPI or SDIO buses. diff --git a/drivers/staging/wfx/Makefile b/drivers/staging/wfx/Makefile deleted file mode 100644 index 0e0cc982ceab..000000000000 --- a/drivers/staging/wfx/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Necessary for CREATE_TRACE_POINTS -CFLAGS_debug.o = -I$(src) - -wfx-y := \ - bh.o \ - hwio.o \ - fwio.o \ - hif_tx_mib.o \ - hif_tx.o \ - hif_rx.o \ - queue.o \ - data_tx.o \ - data_rx.o \ - scan.o \ - sta.o \ - key.o \ - main.o \ - sta.o \ - debug.o -wfx-$(CONFIG_SPI) += bus_spi.o -wfx-$(subst m,y,$(CONFIG_MMC)) += bus_sdio.o - -obj-$(CONFIG_WFX) += wfx.o diff --git a/drivers/staging/wfx/bh.c b/drivers/staging/wfx/bh.c deleted file mode 100644 index ed53d0b45592..000000000000 --- a/drivers/staging/wfx/bh.c +++ /dev/null @@ -1,333 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Interrupt bottom half (BH). - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "bh.h" -#include "wfx.h" -#include "hwio.h" -#include "traces.h" -#include "hif_rx.h" -#include "hif_api_cmd.h" - -static void device_wakeup(struct wfx_dev *wdev) -{ - int max_retry = 3; - - if (!wdev->pdata.gpio_wakeup) - return; - if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0) - return; - - if (wfx_api_older_than(wdev, 1, 4)) { - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - if (!completion_done(&wdev->hif.ctrl_ready)) - usleep_range(2000, 2500); - return; - } - for (;;) { - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - // completion.h does not provide any function to wait - // completion without consume it (a kind of - // wait_for_completion_done_timeout()). So we have to emulate - // it. - if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, - msecs_to_jiffies(2))) { - complete(&wdev->hif.ctrl_ready); - return; - } else if (max_retry-- > 0) { - // Older firmwares have a race in sleep/wake-up process. - // Redo the process is sufficient to unfreeze the - // chip. - dev_err(wdev->dev, "timeout while wake up chip\n"); - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); - usleep_range(2000, 2500); - } else { - dev_err(wdev->dev, "max wake-up retries reached\n"); - return; - } - } -} - -static void device_release(struct wfx_dev *wdev) -{ - if (!wdev->pdata.gpio_wakeup) - return; - - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); -} - -static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) -{ - struct sk_buff *skb; - struct hif_msg *hif; - size_t alloc_len; - size_t computed_len; - int release_count; - int piggyback = 0; - - WARN(read_len > round_down(0xFFF, 2) * sizeof(u16), - "%s: request exceed WFx capability", __func__); - - // Add 2 to take into account piggyback size - alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2); - skb = dev_alloc_skb(alloc_len); - if (!skb) - return -ENOMEM; - - if (wfx_data_read(wdev, skb->data, alloc_len)) - goto err; - - piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2)); - _trace_piggyback(piggyback, false); - - hif = (struct hif_msg *)skb->data; - WARN(hif->encrypted & 0x3, "encryption is unsupported"); - if (WARN(read_len < sizeof(struct hif_msg), "corrupted read")) - goto err; - computed_len = le16_to_cpu(hif->len); - computed_len = round_up(computed_len, 2); - if (computed_len != read_len) { - dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n", - computed_len, read_len); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1, - hif, read_len, true); - goto err; - } - - if (!(hif->id & HIF_ID_IS_INDICATION)) { - (*is_cnf)++; - if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT) - release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs; - else - release_count = 1; - WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter"); - wdev->hif.tx_buffers_used -= release_count; - } - _trace_hif_recv(hif, wdev->hif.tx_buffers_used); - - if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) { - if (hif->seqnum != wdev->hif.rx_seqnum) - dev_warn(wdev->dev, "wrong message sequence: %d != %d\n", - hif->seqnum, wdev->hif.rx_seqnum); - wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1); - } - - skb_put(skb, le16_to_cpu(hif->len)); - // wfx_handle_rx takes care on SKB livetime - wfx_handle_rx(wdev, skb); - if (!wdev->hif.tx_buffers_used) - wake_up(&wdev->hif.tx_buffers_empty); - - return piggyback; - -err: - if (skb) - dev_kfree_skb(skb); - return -EIO; -} - -static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf) -{ - size_t len; - int i; - int ctrl_reg, piggyback; - - piggyback = 0; - for (i = 0; i < max_msg; i++) { - if (piggyback & CTRL_NEXT_LEN_MASK) - ctrl_reg = piggyback; - else if (try_wait_for_completion(&wdev->hif.ctrl_ready)) - ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0); - else - ctrl_reg = 0; - if (!(ctrl_reg & CTRL_NEXT_LEN_MASK)) - return i; - // ctrl_reg units are 16bits words - len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2; - piggyback = rx_helper(wdev, len, num_cnf); - if (piggyback < 0) - return i; - if (!(piggyback & CTRL_WLAN_READY)) - dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n", - piggyback); - } - if (piggyback & CTRL_NEXT_LEN_MASK) { - ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback); - complete(&wdev->hif.ctrl_ready); - if (ctrl_reg) - dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n", - ctrl_reg, piggyback); - } - return i; -} - -static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif) -{ - int ret; - void *data; - bool is_encrypted = false; - size_t len = le16_to_cpu(hif->len); - - WARN(len < sizeof(*hif), "try to send corrupted data"); - - hif->seqnum = wdev->hif.tx_seqnum; - wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1); - - data = hif; - WARN(len > wdev->hw_caps.size_inp_ch_buf, - "%s: request exceed WFx capability: %zu > %d\n", __func__, - len, wdev->hw_caps.size_inp_ch_buf); - len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len); - ret = wfx_data_write(wdev, data, len); - if (ret) - goto end; - - wdev->hif.tx_buffers_used++; - _trace_hif_send(hif, wdev->hif.tx_buffers_used); -end: - if (is_encrypted) - kfree(data); -} - -static int bh_work_tx(struct wfx_dev *wdev, int max_msg) -{ - struct hif_msg *hif; - int i; - - for (i = 0; i < max_msg; i++) { - hif = NULL; - if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) { - if (try_wait_for_completion(&wdev->hif_cmd.ready)) { - WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); - hif = wdev->hif_cmd.buf_send; - } else { - hif = wfx_tx_queues_get(wdev); - } - } - if (!hif) - return i; - tx_helper(wdev, hif); - } - return i; -} - -/* In SDIO mode, it is necessary to make an access to a register to acknowledge - * last received message. It could be possible to restrict this acknowledge to - * SDIO mode and only if last operation was rx. - */ -static void ack_sdio_data(struct wfx_dev *wdev) -{ - u32 cfg_reg; - - config_reg_read(wdev, &cfg_reg); - if (cfg_reg & 0xFF) { - dev_warn(wdev->dev, "chip reports errors: %02x\n", - cfg_reg & 0xFF); - config_reg_write_bits(wdev, 0xFF, 0x00); - } -} - -static void bh_work(struct work_struct *work) -{ - struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh); - int stats_req = 0, stats_cnf = 0, stats_ind = 0; - bool release_chip = false, last_op_is_rx = false; - int num_tx, num_rx; - - device_wakeup(wdev); - do { - num_tx = bh_work_tx(wdev, 32); - stats_req += num_tx; - if (num_tx) - last_op_is_rx = false; - num_rx = bh_work_rx(wdev, 32, &stats_cnf); - stats_ind += num_rx; - if (num_rx) - last_op_is_rx = true; - } while (num_rx || num_tx); - stats_ind -= stats_cnf; - - if (last_op_is_rx) - ack_sdio_data(wdev); - if (!wdev->hif.tx_buffers_used && !work_pending(work)) { - device_release(wdev); - release_chip = true; - } - _trace_bh_stats(stats_ind, stats_req, stats_cnf, - wdev->hif.tx_buffers_used, release_chip); -} - -/* - * An IRQ from chip did occur - */ -void wfx_bh_request_rx(struct wfx_dev *wdev) -{ - u32 cur, prev; - - control_reg_read(wdev, &cur); - prev = atomic_xchg(&wdev->hif.ctrl_reg, cur); - complete(&wdev->hif.ctrl_ready); - queue_work(system_highpri_wq, &wdev->hif.bh); - - if (!(cur & CTRL_NEXT_LEN_MASK)) - dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n", - cur); - if (prev != 0) - dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n", - prev, cur); -} - -/* - * Driver want to send data - */ -void wfx_bh_request_tx(struct wfx_dev *wdev) -{ - queue_work(system_highpri_wq, &wdev->hif.bh); -} - -/* - * If IRQ is not available, this function allow to manually poll the control - * register and simulate an IRQ ahen an event happened. - * - * Note that the device has a bug: If an IRQ raise while host read control - * register, the IRQ is lost. So, use this function carefully (only duing - * device initialisation). - */ -void wfx_bh_poll_irq(struct wfx_dev *wdev) -{ - ktime_t now, start; - u32 reg; - - WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ"); - start = ktime_get(); - for (;;) { - control_reg_read(wdev, ®); - now = ktime_get(); - if (reg & 0xFFF) - break; - if (ktime_after(now, ktime_add_ms(start, 1000))) { - dev_err(wdev->dev, "time out while polling control register\n"); - return; - } - udelay(200); - } - wfx_bh_request_rx(wdev); -} - -void wfx_bh_register(struct wfx_dev *wdev) -{ - INIT_WORK(&wdev->hif.bh, bh_work); - init_completion(&wdev->hif.ctrl_ready); - init_waitqueue_head(&wdev->hif.tx_buffers_empty); -} - -void wfx_bh_unregister(struct wfx_dev *wdev) -{ - flush_work(&wdev->hif.bh); -} diff --git a/drivers/staging/wfx/bh.h b/drivers/staging/wfx/bh.h deleted file mode 100644 index 78c49329e22a..000000000000 --- a/drivers/staging/wfx/bh.h +++ /dev/null @@ -1,33 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Interrupt bottom half. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_BH_H -#define WFX_BH_H - -#include -#include -#include - -struct wfx_dev; - -struct wfx_hif { - struct work_struct bh; - struct completion ctrl_ready; - wait_queue_head_t tx_buffers_empty; - atomic_t ctrl_reg; - int rx_seqnum; - int tx_seqnum; - int tx_buffers_used; -}; - -void wfx_bh_register(struct wfx_dev *wdev); -void wfx_bh_unregister(struct wfx_dev *wdev); -void wfx_bh_request_rx(struct wfx_dev *wdev); -void wfx_bh_request_tx(struct wfx_dev *wdev); -void wfx_bh_poll_irq(struct wfx_dev *wdev); - -#endif /* WFX_BH_H */ diff --git a/drivers/staging/wfx/bus.h b/drivers/staging/wfx/bus.h deleted file mode 100644 index ca04b3da6204..000000000000 --- a/drivers/staging/wfx/bus.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Common bus abstraction layer. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_BUS_H -#define WFX_BUS_H - -#include -#include - -#define WFX_REG_CONFIG 0x0 -#define WFX_REG_CONTROL 0x1 -#define WFX_REG_IN_OUT_QUEUE 0x2 -#define WFX_REG_AHB_DPORT 0x3 -#define WFX_REG_BASE_ADDR 0x4 -#define WFX_REG_SRAM_DPORT 0x5 -#define WFX_REG_SET_GEN_R_W 0x6 -#define WFX_REG_FRAME_OUT 0x7 - -struct hwbus_ops { - int (*copy_from_io)(void *bus_priv, unsigned int addr, - void *dst, size_t count); - int (*copy_to_io)(void *bus_priv, unsigned int addr, - const void *src, size_t count); - int (*irq_subscribe)(void *bus_priv); - int (*irq_unsubscribe)(void *bus_priv); - void (*lock)(void *bus_priv); - void (*unlock)(void *bus_priv); - size_t (*align_size)(void *bus_priv, size_t size); -}; - -extern struct sdio_driver wfx_sdio_driver; -extern struct spi_driver wfx_spi_driver; - -#endif diff --git a/drivers/staging/wfx/bus_sdio.c b/drivers/staging/wfx/bus_sdio.c deleted file mode 100644 index e06d7e1ebe9c..000000000000 --- a/drivers/staging/wfx/bus_sdio.c +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SDIO interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include -#include -#include -#include - -#include "bus.h" -#include "wfx.h" -#include "hwio.h" -#include "main.h" -#include "bh.h" - -static const struct wfx_platform_data wfx_sdio_pdata = { - .file_fw = "wfm_wf200", - .file_pds = "wf200.pds", -}; - -struct wfx_sdio_priv { - struct sdio_func *func; - struct wfx_dev *core; - u8 buf_id_tx; - u8 buf_id_rx; - int of_irq; -}; - -static int wfx_sdio_copy_from_io(void *priv, unsigned int reg_id, - void *dst, size_t count) -{ - struct wfx_sdio_priv *bus = priv; - unsigned int sdio_addr = reg_id << 2; - int ret; - - WARN(reg_id > 7, "chip only has 7 registers"); - WARN(((uintptr_t)dst) & 3, "unaligned buffer size"); - WARN(count & 3, "unaligned buffer address"); - - /* Use queue mode buffers */ - if (reg_id == WFX_REG_IN_OUT_QUEUE) - sdio_addr |= (bus->buf_id_rx + 1) << 7; - ret = sdio_memcpy_fromio(bus->func, dst, sdio_addr, count); - if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) - bus->buf_id_rx = (bus->buf_id_rx + 1) % 4; - - return ret; -} - -static int wfx_sdio_copy_to_io(void *priv, unsigned int reg_id, - const void *src, size_t count) -{ - struct wfx_sdio_priv *bus = priv; - unsigned int sdio_addr = reg_id << 2; - int ret; - - WARN(reg_id > 7, "chip only has 7 registers"); - WARN(((uintptr_t)src) & 3, "unaligned buffer size"); - WARN(count & 3, "unaligned buffer address"); - - /* Use queue mode buffers */ - if (reg_id == WFX_REG_IN_OUT_QUEUE) - sdio_addr |= bus->buf_id_tx << 7; - // FIXME: discards 'const' qualifier for src - ret = sdio_memcpy_toio(bus->func, sdio_addr, (void *)src, count); - if (!ret && reg_id == WFX_REG_IN_OUT_QUEUE) - bus->buf_id_tx = (bus->buf_id_tx + 1) % 32; - - return ret; -} - -static void wfx_sdio_lock(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_claim_host(bus->func); -} - -static void wfx_sdio_unlock(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_release_host(bus->func); -} - -static void wfx_sdio_irq_handler(struct sdio_func *func) -{ - struct wfx_sdio_priv *bus = sdio_get_drvdata(func); - - wfx_bh_request_rx(bus->core); -} - -static irqreturn_t wfx_sdio_irq_handler_ext(int irq, void *priv) -{ - struct wfx_sdio_priv *bus = priv; - - sdio_claim_host(bus->func); - wfx_bh_request_rx(bus->core); - sdio_release_host(bus->func); - return IRQ_HANDLED; -} - -static int wfx_sdio_irq_subscribe(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - u32 flags; - int ret; - u8 cccr; - - if (!bus->of_irq) { - sdio_claim_host(bus->func); - ret = sdio_claim_irq(bus->func, wfx_sdio_irq_handler); - sdio_release_host(bus->func); - return ret; - } - - sdio_claim_host(bus->func); - cccr = sdio_f0_readb(bus->func, SDIO_CCCR_IENx, NULL); - cccr |= BIT(0); - cccr |= BIT(bus->func->num); - sdio_f0_writeb(bus->func, cccr, SDIO_CCCR_IENx, NULL); - sdio_release_host(bus->func); - flags = irq_get_trigger_type(bus->of_irq); - if (!flags) - flags = IRQF_TRIGGER_HIGH; - flags |= IRQF_ONESHOT; - return devm_request_threaded_irq(&bus->func->dev, bus->of_irq, NULL, - wfx_sdio_irq_handler_ext, flags, - "wfx", bus); -} - -static int wfx_sdio_irq_unsubscribe(void *priv) -{ - struct wfx_sdio_priv *bus = priv; - int ret; - - if (bus->of_irq) - devm_free_irq(&bus->func->dev, bus->of_irq, bus); - sdio_claim_host(bus->func); - ret = sdio_release_irq(bus->func); - sdio_release_host(bus->func); - return ret; -} - -static size_t wfx_sdio_align_size(void *priv, size_t size) -{ - struct wfx_sdio_priv *bus = priv; - - return sdio_align_size(bus->func, size); -} - -static const struct hwbus_ops wfx_sdio_hwbus_ops = { - .copy_from_io = wfx_sdio_copy_from_io, - .copy_to_io = wfx_sdio_copy_to_io, - .irq_subscribe = wfx_sdio_irq_subscribe, - .irq_unsubscribe = wfx_sdio_irq_unsubscribe, - .lock = wfx_sdio_lock, - .unlock = wfx_sdio_unlock, - .align_size = wfx_sdio_align_size, -}; - -static const struct of_device_id wfx_sdio_of_match[] = { - { .compatible = "silabs,wfx-sdio" }, - { .compatible = "silabs,wf200" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wfx_sdio_of_match); - -static int wfx_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct device_node *np = func->dev.of_node; - struct wfx_sdio_priv *bus; - int ret; - - if (func->num != 1) { - dev_err(&func->dev, "SDIO function number is %d while it should always be 1 (unsupported chip?)\n", - func->num); - return -ENODEV; - } - - bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - - if (np) { - if (!of_match_node(wfx_sdio_of_match, np)) { - dev_warn(&func->dev, "no compatible device found in DT\n"); - return -ENODEV; - } - bus->of_irq = irq_of_parse_and_map(np, 0); - } else { - dev_warn(&func->dev, - "device is not declared in DT, features will be limited\n"); - // FIXME: ignore VID/PID and only rely on device tree - // return -ENODEV; - } - - bus->func = func; - sdio_set_drvdata(func, bus); - func->card->quirks |= MMC_QUIRK_LENIENT_FN0 | - MMC_QUIRK_BLKSZ_FOR_BYTE_MODE | - MMC_QUIRK_BROKEN_BYTE_MODE_512; - - sdio_claim_host(func); - ret = sdio_enable_func(func); - // Block of 64 bytes is more efficient than 512B for frame sizes < 4k - sdio_set_block_size(func, 64); - sdio_release_host(func); - if (ret) - goto err0; - - bus->core = wfx_init_common(&func->dev, &wfx_sdio_pdata, - &wfx_sdio_hwbus_ops, bus); - if (!bus->core) { - ret = -EIO; - goto err1; - } - - ret = wfx_probe(bus->core); - if (ret) - goto err1; - - return 0; - -err1: - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -err0: - return ret; -} - -static void wfx_sdio_remove(struct sdio_func *func) -{ - struct wfx_sdio_priv *bus = sdio_get_drvdata(func); - - wfx_release(bus->core); - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -} - -#define SDIO_VENDOR_ID_SILABS 0x0000 -#define SDIO_DEVICE_ID_SILABS_WF200 0x1000 -static const struct sdio_device_id wfx_sdio_ids[] = { - { SDIO_DEVICE(SDIO_VENDOR_ID_SILABS, SDIO_DEVICE_ID_SILABS_WF200) }, - // FIXME: ignore VID/PID and only rely on device tree - // { SDIO_DEVICE(SDIO_ANY_ID, SDIO_ANY_ID) }, - { }, -}; -MODULE_DEVICE_TABLE(sdio, wfx_sdio_ids); - -struct sdio_driver wfx_sdio_driver = { - .name = "wfx-sdio", - .id_table = wfx_sdio_ids, - .probe = wfx_sdio_probe, - .remove = wfx_sdio_remove, - .drv = { - .owner = THIS_MODULE, - .of_match_table = wfx_sdio_of_match, - } -}; diff --git a/drivers/staging/wfx/bus_spi.c b/drivers/staging/wfx/bus_spi.c deleted file mode 100644 index a99125d1a30d..000000000000 --- a/drivers/staging/wfx/bus_spi.c +++ /dev/null @@ -1,271 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * SPI interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2011, Sagrad Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include -#include -#include -#include - -#include "bus.h" -#include "wfx.h" -#include "hwio.h" -#include "main.h" -#include "bh.h" - -#define SET_WRITE 0x7FFF /* usage: and operation */ -#define SET_READ 0x8000 /* usage: or operation */ - -#define WFX_RESET_INVERTED 1 - -static const struct wfx_platform_data wfx_spi_pdata = { - .file_fw = "wfm_wf200", - .file_pds = "wf200.pds", - .use_rising_clk = true, -}; - -struct wfx_spi_priv { - struct spi_device *func; - struct wfx_dev *core; - struct gpio_desc *gpio_reset; - bool need_swab; -}; - -/* - * WFx chip read data 16bits at time and place them directly into (little - * endian) CPU register. So, chip expect byte order like "B1 B0 B3 B2" (while - * LE is "B0 B1 B2 B3" and BE is "B3 B2 B1 B0") - * - * A little endian host with bits_per_word == 16 should do the right job - * natively. The code below to support big endian host and commonly used SPI - * 8bits. - */ -static int wfx_spi_copy_from_io(void *priv, unsigned int addr, - void *dst, size_t count) -{ - struct wfx_spi_priv *bus = priv; - u16 regaddr = (addr << 12) | (count / 2) | SET_READ; - struct spi_message m; - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .rx_buf = dst, - .len = count, - }; - u16 *dst16 = dst; - int ret, i; - - WARN(count % 2, "buffer size must be a multiple of 2"); - - cpu_to_le16s(®addr); - if (bus->need_swab) - swab16s(®addr); - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - ret = spi_sync(bus->func, &m); - - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&dst16[i]); - return ret; -} - -static int wfx_spi_copy_to_io(void *priv, unsigned int addr, - const void *src, size_t count) -{ - struct wfx_spi_priv *bus = priv; - u16 regaddr = (addr << 12) | (count / 2); - // FIXME: use a bounce buffer - u16 *src16 = (void *)src; - int ret, i; - struct spi_message m; - struct spi_transfer t_addr = { - .tx_buf = ®addr, - .len = sizeof(regaddr), - }; - struct spi_transfer t_msg = { - .tx_buf = src, - .len = count, - }; - - WARN(count % 2, "buffer size must be a multiple of 2"); - WARN(regaddr & SET_READ, "bad addr or size overflow"); - - cpu_to_le16s(®addr); - - // Register address and CONFIG content always use 16bit big endian - // ("BADC" order) - if (bus->need_swab) - swab16s(®addr); - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&src16[i]); - - spi_message_init(&m); - spi_message_add_tail(&t_addr, &m); - spi_message_add_tail(&t_msg, &m); - ret = spi_sync(bus->func, &m); - - if (bus->need_swab && addr == WFX_REG_CONFIG) - for (i = 0; i < count / 2; i++) - swab16s(&src16[i]); - return ret; -} - -static void wfx_spi_lock(void *priv) -{ -} - -static void wfx_spi_unlock(void *priv) -{ -} - -static irqreturn_t wfx_spi_irq_handler(int irq, void *priv) -{ - struct wfx_spi_priv *bus = priv; - - wfx_bh_request_rx(bus->core); - return IRQ_HANDLED; -} - -static int wfx_spi_irq_subscribe(void *priv) -{ - struct wfx_spi_priv *bus = priv; - u32 flags; - - flags = irq_get_trigger_type(bus->func->irq); - if (!flags) - flags = IRQF_TRIGGER_HIGH; - flags |= IRQF_ONESHOT; - return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL, - wfx_spi_irq_handler, IRQF_ONESHOT, - "wfx", bus); -} - -static int wfx_spi_irq_unsubscribe(void *priv) -{ - struct wfx_spi_priv *bus = priv; - - devm_free_irq(&bus->func->dev, bus->func->irq, bus); - return 0; -} - -static size_t wfx_spi_align_size(void *priv, size_t size) -{ - // Most of SPI controllers avoid DMA if buffer size is not 32bit aligned - return ALIGN(size, 4); -} - -static const struct hwbus_ops wfx_spi_hwbus_ops = { - .copy_from_io = wfx_spi_copy_from_io, - .copy_to_io = wfx_spi_copy_to_io, - .irq_subscribe = wfx_spi_irq_subscribe, - .irq_unsubscribe = wfx_spi_irq_unsubscribe, - .lock = wfx_spi_lock, - .unlock = wfx_spi_unlock, - .align_size = wfx_spi_align_size, -}; - -static int wfx_spi_probe(struct spi_device *func) -{ - struct wfx_spi_priv *bus; - int ret; - - if (!func->bits_per_word) - func->bits_per_word = 16; - ret = spi_setup(func); - if (ret) - return ret; - // Trace below is also displayed by spi_setup() if compiled with DEBUG - dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n", - func->chip_select, func->mode, func->bits_per_word, - func->max_speed_hz); - if (func->bits_per_word != 16 && func->bits_per_word != 8) - dev_warn(&func->dev, "unusual bits/word value: %d\n", - func->bits_per_word); - if (func->max_speed_hz > 50000000) - dev_warn(&func->dev, "%dHz is a very high speed\n", - func->max_speed_hz); - - bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL); - if (!bus) - return -ENOMEM; - bus->func = func; - if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) - bus->need_swab = true; - spi_set_drvdata(func, bus); - - bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset", - GPIOD_OUT_LOW); - if (IS_ERR(bus->gpio_reset)) - return PTR_ERR(bus->gpio_reset); - if (!bus->gpio_reset) { - dev_warn(&func->dev, - "gpio reset is not defined, trying to load firmware anyway\n"); - } else { - gpiod_set_consumer_name(bus->gpio_reset, "wfx reset"); - if (spi_get_device_id(func)->driver_data & WFX_RESET_INVERTED) - gpiod_toggle_active_low(bus->gpio_reset); - gpiod_set_value_cansleep(bus->gpio_reset, 1); - usleep_range(100, 150); - gpiod_set_value_cansleep(bus->gpio_reset, 0); - usleep_range(2000, 2500); - } - - bus->core = wfx_init_common(&func->dev, &wfx_spi_pdata, - &wfx_spi_hwbus_ops, bus); - if (!bus->core) - return -EIO; - - return wfx_probe(bus->core); -} - -static int wfx_spi_remove(struct spi_device *func) -{ - struct wfx_spi_priv *bus = spi_get_drvdata(func); - - wfx_release(bus->core); - return 0; -} - -/* - * For dynamic driver binding, kernel does not use OF to match driver. It only - * use modalias and modalias is a copy of 'compatible' DT node with vendor - * stripped. - */ -static const struct spi_device_id wfx_spi_id[] = { - { "wfx-spi", WFX_RESET_INVERTED }, - { "wf200", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, wfx_spi_id); - -#ifdef CONFIG_OF -static const struct of_device_id wfx_spi_of_match[] = { - { .compatible = "silabs,wfx-spi", .data = (void *)WFX_RESET_INVERTED }, - { .compatible = "silabs,wf200" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wfx_spi_of_match); -#endif - -struct spi_driver wfx_spi_driver = { - .driver = { - .name = "wfx-spi", - .of_match_table = of_match_ptr(wfx_spi_of_match), - }, - .id_table = wfx_spi_id, - .probe = wfx_spi_probe, - .remove = wfx_spi_remove, -}; diff --git a/drivers/staging/wfx/data_rx.c b/drivers/staging/wfx/data_rx.c deleted file mode 100644 index 385f2d42a0e2..000000000000 --- a/drivers/staging/wfx/data_rx.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "data_rx.h" -#include "wfx.h" -#include "bh.h" -#include "sta.h" - -static void wfx_rx_handle_ba(struct wfx_vif *wvif, struct ieee80211_mgmt *mgmt) -{ - int params, tid; - - if (wfx_api_older_than(wvif->wdev, 3, 6)) - return; - - switch (mgmt->u.action.u.addba_req.action_code) { - case WLAN_ACTION_ADDBA_REQ: - params = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - tid = (params & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - ieee80211_start_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); - break; - case WLAN_ACTION_DELBA: - params = le16_to_cpu(mgmt->u.action.u.delba.params); - tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; - ieee80211_stop_rx_ba_session_offl(wvif->vif, mgmt->sa, tid); - break; - } -} - -void wfx_rx_cb(struct wfx_vif *wvif, - const struct hif_ind_rx *arg, struct sk_buff *skb) -{ - struct ieee80211_rx_status *hdr = IEEE80211_SKB_RXCB(skb); - struct ieee80211_hdr *frame = (struct ieee80211_hdr *)skb->data; - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; - - memset(hdr, 0, sizeof(*hdr)); - - if (arg->status == HIF_STATUS_RX_FAIL_MIC) - hdr->flag |= RX_FLAG_MMIC_ERROR | RX_FLAG_IV_STRIPPED; - else if (arg->status) - goto drop; - - if (skb->len < sizeof(struct ieee80211_pspoll)) { - dev_warn(wvif->wdev->dev, "malformed SDU received\n"); - goto drop; - } - - hdr->band = NL80211_BAND_2GHZ; - hdr->freq = ieee80211_channel_to_frequency(arg->channel_number, - hdr->band); - - if (arg->rxed_rate >= 14) { - hdr->encoding = RX_ENC_HT; - hdr->rate_idx = arg->rxed_rate - 14; - } else if (arg->rxed_rate >= 4) { - hdr->rate_idx = arg->rxed_rate - 2; - } else { - hdr->rate_idx = arg->rxed_rate; - } - - if (!arg->rcpi_rssi) { - hdr->flag |= RX_FLAG_NO_SIGNAL_VAL; - dev_info(wvif->wdev->dev, "received frame without RSSI data\n"); - } - hdr->signal = arg->rcpi_rssi / 2 - 110; - hdr->antenna = 0; - - if (arg->encryp) - hdr->flag |= RX_FLAG_DECRYPTED; - - // Block ack negotiation is offloaded by the firmware. However, - // re-ordering must be done by the mac80211. - if (ieee80211_is_action(frame->frame_control) && - mgmt->u.action.category == WLAN_CATEGORY_BACK && - skb->len > IEEE80211_MIN_ACTION_SIZE) { - wfx_rx_handle_ba(wvif, mgmt); - goto drop; - } - - ieee80211_rx_irqsafe(wvif->wdev->hw, skb); - return; - -drop: - dev_kfree_skb(skb); -} diff --git a/drivers/staging/wfx/data_rx.h b/drivers/staging/wfx/data_rx.h deleted file mode 100644 index 4c0da37f2084..000000000000 --- a/drivers/staging/wfx/data_rx.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_DATA_RX_H -#define WFX_DATA_RX_H - -struct wfx_vif; -struct sk_buff; -struct hif_ind_rx; - -void wfx_rx_cb(struct wfx_vif *wvif, - const struct hif_ind_rx *arg, struct sk_buff *skb); - -#endif /* WFX_DATA_RX_H */ diff --git a/drivers/staging/wfx/data_tx.c b/drivers/staging/wfx/data_tx.c deleted file mode 100644 index 36b36ef39d05..000000000000 --- a/drivers/staging/wfx/data_tx.c +++ /dev/null @@ -1,585 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "data_tx.h" -#include "wfx.h" -#include "bh.h" -#include "sta.h" -#include "queue.h" -#include "debug.h" -#include "traces.h" -#include "hif_tx_mib.h" - -static int wfx_get_hw_rate(struct wfx_dev *wdev, - const struct ieee80211_tx_rate *rate) -{ - struct ieee80211_supported_band *band; - - if (rate->idx < 0) - return -1; - if (rate->flags & IEEE80211_TX_RC_MCS) { - if (rate->idx > 7) { - WARN(1, "wrong rate->idx value: %d", rate->idx); - return -1; - } - return rate->idx + 14; - } - // WFx only support 2GHz, else band information should be retrieved - // from ieee80211_tx_info - band = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; - if (rate->idx >= band->n_bitrates) { - WARN(1, "wrong rate->idx value: %d", rate->idx); - return -1; - } - return band->bitrates[rate->idx].hw_value; -} - -/* TX policy cache implementation */ - -static void wfx_tx_policy_build(struct wfx_vif *wvif, struct tx_policy *policy, - struct ieee80211_tx_rate *rates) -{ - struct wfx_dev *wdev = wvif->wdev; - int i, rateid; - u8 count; - - WARN(rates[0].idx < 0, "invalid rate policy"); - memset(policy, 0, sizeof(*policy)); - for (i = 0; i < IEEE80211_TX_MAX_RATES; ++i) { - if (rates[i].idx < 0) - break; - WARN_ON(rates[i].count > 15); - rateid = wfx_get_hw_rate(wdev, &rates[i]); - // Pack two values in each byte of policy->rates - count = rates[i].count; - if (rateid % 2) - count <<= 4; - policy->rates[rateid / 2] |= count; - } -} - -static bool tx_policy_is_equal(const struct tx_policy *a, - const struct tx_policy *b) -{ - return !memcmp(a->rates, b->rates, sizeof(a->rates)); -} - -static int wfx_tx_policy_find(struct tx_policy_cache *cache, - struct tx_policy *wanted) -{ - struct tx_policy *it; - - list_for_each_entry(it, &cache->used, link) - if (tx_policy_is_equal(wanted, it)) - return it - cache->cache; - list_for_each_entry(it, &cache->free, link) - if (tx_policy_is_equal(wanted, it)) - return it - cache->cache; - return -1; -} - -static void wfx_tx_policy_use(struct tx_policy_cache *cache, - struct tx_policy *entry) -{ - ++entry->usage_count; - list_move(&entry->link, &cache->used); -} - -static int wfx_tx_policy_release(struct tx_policy_cache *cache, - struct tx_policy *entry) -{ - int ret = --entry->usage_count; - - if (!ret) - list_move(&entry->link, &cache->free); - return ret; -} - -static int wfx_tx_policy_get(struct wfx_vif *wvif, - struct ieee80211_tx_rate *rates, bool *renew) -{ - int idx; - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - struct tx_policy wanted; - - wfx_tx_policy_build(wvif, &wanted, rates); - - spin_lock_bh(&cache->lock); - if (list_empty(&cache->free)) { - WARN(1, "unable to get a valid Tx policy"); - spin_unlock_bh(&cache->lock); - return HIF_TX_RETRY_POLICY_INVALID; - } - idx = wfx_tx_policy_find(cache, &wanted); - if (idx >= 0) { - *renew = false; - } else { - struct tx_policy *entry; - *renew = true; - /* If policy is not found create a new one - * using the oldest entry in "free" list - */ - entry = list_entry(cache->free.prev, struct tx_policy, link); - memcpy(entry->rates, wanted.rates, sizeof(entry->rates)); - entry->uploaded = false; - entry->usage_count = 0; - idx = entry - cache->cache; - } - wfx_tx_policy_use(cache, &cache->cache[idx]); - if (list_empty(&cache->free)) - ieee80211_stop_queues(wvif->wdev->hw); - spin_unlock_bh(&cache->lock); - return idx; -} - -static void wfx_tx_policy_put(struct wfx_vif *wvif, int idx) -{ - int usage, locked; - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - - if (idx == HIF_TX_RETRY_POLICY_INVALID) - return; - spin_lock_bh(&cache->lock); - locked = list_empty(&cache->free); - usage = wfx_tx_policy_release(cache, &cache->cache[idx]); - if (locked && !usage) - ieee80211_wake_queues(wvif->wdev->hw); - spin_unlock_bh(&cache->lock); -} - -static int wfx_tx_policy_upload(struct wfx_vif *wvif) -{ - struct tx_policy *policies = wvif->tx_policy_cache.cache; - u8 tmp_rates[12]; - int i, is_used; - - do { - spin_lock_bh(&wvif->tx_policy_cache.lock); - for (i = 0; i < ARRAY_SIZE(wvif->tx_policy_cache.cache); ++i) { - is_used = memzcmp(policies[i].rates, - sizeof(policies[i].rates)); - if (!policies[i].uploaded && is_used) - break; - } - if (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)) { - policies[i].uploaded = true; - memcpy(tmp_rates, policies[i].rates, sizeof(tmp_rates)); - spin_unlock_bh(&wvif->tx_policy_cache.lock); - hif_set_tx_rate_retry_policy(wvif, i, tmp_rates); - } else { - spin_unlock_bh(&wvif->tx_policy_cache.lock); - } - } while (i < ARRAY_SIZE(wvif->tx_policy_cache.cache)); - return 0; -} - -void wfx_tx_policy_upload_work(struct work_struct *work) -{ - struct wfx_vif *wvif = - container_of(work, struct wfx_vif, tx_policy_upload_work); - - wfx_tx_policy_upload(wvif); - wfx_tx_unlock(wvif->wdev); -} - -void wfx_tx_policy_init(struct wfx_vif *wvif) -{ - struct tx_policy_cache *cache = &wvif->tx_policy_cache; - int i; - - memset(cache, 0, sizeof(*cache)); - - spin_lock_init(&cache->lock); - INIT_LIST_HEAD(&cache->used); - INIT_LIST_HEAD(&cache->free); - - for (i = 0; i < ARRAY_SIZE(cache->cache); ++i) - list_add(&cache->cache[i].link, &cache->free); -} - -/* Tx implementation */ - -static bool ieee80211_is_action_back(struct ieee80211_hdr *hdr) -{ - struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; - - if (!ieee80211_is_action(mgmt->frame_control)) - return false; - if (mgmt->u.action.category != WLAN_CATEGORY_BACK) - return false; - return true; -} - -static u8 wfx_tx_get_link_id(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct ieee80211_hdr *hdr) -{ - struct wfx_sta_priv *sta_priv = - sta ? (struct wfx_sta_priv *)&sta->drv_priv : NULL; - const u8 *da = ieee80211_get_DA(hdr); - - if (sta_priv && sta_priv->link_id) - return sta_priv->link_id; - if (wvif->vif->type != NL80211_IFTYPE_AP) - return 0; - if (is_multicast_ether_addr(da)) - return 0; - return HIF_LINK_ID_NOT_ASSOCIATED; -} - -static void wfx_tx_fixup_rates(struct ieee80211_tx_rate *rates) -{ - int i; - bool finished; - - // Firmware is not able to mix rates with different flags - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - rates[i].flags |= IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) - rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; - if (!(rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)) - rates[i].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; - } - - // Sort rates and remove duplicates - do { - finished = true; - for (i = 0; i < IEEE80211_TX_MAX_RATES - 1; i++) { - if (rates[i + 1].idx == rates[i].idx && - rates[i].idx != -1) { - rates[i].count += rates[i + 1].count; - if (rates[i].count > 15) - rates[i].count = 15; - rates[i + 1].idx = -1; - rates[i + 1].count = 0; - - finished = false; - } - if (rates[i + 1].idx > rates[i].idx) { - swap(rates[i + 1], rates[i]); - finished = false; - } - } - } while (!finished); - // Ensure that MCS0 or 1Mbps is present at the end of the retry list - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - if (rates[i].idx == 0) - break; - if (rates[i].idx == -1) { - rates[i].idx = 0; - rates[i].count = 8; // == hw->max_rate_tries - rates[i].flags = rates[i - 1].flags & - IEEE80211_TX_RC_MCS; - break; - } - } - // All retries use long GI - for (i = 1; i < IEEE80211_TX_MAX_RATES; i++) - rates[i].flags &= ~IEEE80211_TX_RC_SHORT_GI; -} - -static u8 wfx_tx_get_rate_id(struct wfx_vif *wvif, - struct ieee80211_tx_info *tx_info) -{ - bool tx_policy_renew = false; - u8 rate_id; - - rate_id = wfx_tx_policy_get(wvif, - tx_info->driver_rates, &tx_policy_renew); - if (rate_id == HIF_TX_RETRY_POLICY_INVALID) - dev_warn(wvif->wdev->dev, "unable to get a valid Tx policy"); - - if (tx_policy_renew) { - wfx_tx_lock(wvif->wdev); - if (!schedule_work(&wvif->tx_policy_upload_work)) - wfx_tx_unlock(wvif->wdev); - } - return rate_id; -} - -static int wfx_tx_get_frame_format(struct ieee80211_tx_info *tx_info) -{ - if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_MCS)) - return HIF_FRAME_FORMAT_NON_HT; - else if (!(tx_info->driver_rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) - return HIF_FRAME_FORMAT_MIXED_FORMAT_HT; - else - return HIF_FRAME_FORMAT_GF_HT_11N; -} - -static int wfx_tx_get_icv_len(struct ieee80211_key_conf *hw_key) -{ - int mic_space; - - if (!hw_key) - return 0; - if (hw_key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) - return 0; - mic_space = (hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) ? 8 : 0; - return hw_key->icv_len + mic_space; -} - -static int wfx_tx_inner(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct sk_buff *skb) -{ - struct hif_msg *hif_msg; - struct hif_req_tx *req; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - int queue_id = skb_get_queue_mapping(skb); - size_t offset = (size_t)skb->data & 3; - int wmsg_len = sizeof(struct hif_msg) + - sizeof(struct hif_req_tx) + offset; - - WARN(queue_id >= IEEE80211_NUM_ACS, "unsupported queue_id"); - wfx_tx_fixup_rates(tx_info->driver_rates); - - // From now tx_info->control is unusable - memset(tx_info->rate_driver_data, 0, sizeof(struct wfx_tx_priv)); - - // Fill hif_msg - WARN(skb_headroom(skb) < wmsg_len, "not enough space in skb"); - WARN(offset & 1, "attempt to transmit an unaligned frame"); - skb_put(skb, wfx_tx_get_icv_len(hw_key)); - skb_push(skb, wmsg_len); - memset(skb->data, 0, wmsg_len); - hif_msg = (struct hif_msg *)skb->data; - hif_msg->len = cpu_to_le16(skb->len); - hif_msg->id = HIF_REQ_ID_TX; - hif_msg->interface = wvif->id; - if (skb->len > wvif->wdev->hw_caps.size_inp_ch_buf) { - dev_warn(wvif->wdev->dev, - "requested frame size (%d) is larger than maximum supported (%d)\n", - skb->len, wvif->wdev->hw_caps.size_inp_ch_buf); - skb_pull(skb, wmsg_len); - return -EIO; - } - - // Fill tx request - req = (struct hif_req_tx *)hif_msg->body; - // packet_id just need to be unique on device. 32bits are more than - // necessary for that task, so we tae advantage of it to add some extra - // data for debug. - req->packet_id = atomic_add_return(1, &wvif->wdev->packet_id) & 0xFFFF; - req->packet_id |= IEEE80211_SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl)) << 16; - req->packet_id |= queue_id << 28; - - req->fc_offset = offset; - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - req->after_dtim = 1; - req->peer_sta_id = wfx_tx_get_link_id(wvif, sta, hdr); - // Queue index are inverted between firmware and Linux - req->queue_id = 3 - queue_id; - req->retry_policy_index = wfx_tx_get_rate_id(wvif, tx_info); - req->frame_format = wfx_tx_get_frame_format(tx_info); - if (tx_info->driver_rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - req->short_gi = 1; - - // Auxiliary operations - wfx_tx_queues_put(wvif, skb); - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - schedule_work(&wvif->update_tim_work); - wfx_bh_request_tx(wvif->wdev); - return 0; -} - -void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif; - struct ieee80211_sta *sta = control ? control->sta : NULL; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - size_t driver_data_room = sizeof_field(struct ieee80211_tx_info, - rate_driver_data); - - compiletime_assert(sizeof(struct wfx_tx_priv) <= driver_data_room, - "struct tx_priv is too large"); - WARN(skb->next || skb->prev, "skb is already member of a list"); - // control.vif can be NULL for injected frames - if (tx_info->control.vif) - wvif = (struct wfx_vif *)tx_info->control.vif->drv_priv; - else - wvif = wvif_iterate(wdev, NULL); - if (WARN_ON(!wvif)) - goto drop; - // Because of TX_AMPDU_SETUP_IN_HW, mac80211 does not try to send any - // BlockAck session management frame. The check below exist just in case. - if (ieee80211_is_action_back(hdr)) { - dev_info(wdev->dev, "drop BA action\n"); - goto drop; - } - if (wfx_tx_inner(wvif, sta, skb)) - goto drop; - - return; - -drop: - ieee80211_tx_status_irqsafe(wdev->hw, skb); -} - -static void wfx_skb_dtor(struct wfx_vif *wvif, struct sk_buff *skb) -{ - struct hif_msg *hif = (struct hif_msg *)skb->data; - struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - unsigned int offset = sizeof(struct hif_msg) + - sizeof(struct hif_req_tx) + - req->fc_offset; - - if (!wvif) { - pr_warn("%s: vif associated with the skb does not exist anymore\n", __func__); - return; - } - wfx_tx_policy_put(wvif, req->retry_policy_index); - skb_pull(skb, offset); - ieee80211_tx_status_irqsafe(wvif->wdev->hw, skb); -} - -static void wfx_tx_fill_rates(struct wfx_dev *wdev, - struct ieee80211_tx_info *tx_info, - const struct hif_cnf_tx *arg) -{ - struct ieee80211_tx_rate *rate; - int tx_count; - int i; - - tx_count = arg->ack_failures; - if (!arg->status || arg->ack_failures) - tx_count += 1; // Also report success - for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { - rate = &tx_info->status.rates[i]; - if (rate->idx < 0) - break; - if (tx_count < rate->count && - arg->status == HIF_STATUS_TX_FAIL_RETRIES && - arg->ack_failures) - dev_dbg(wdev->dev, "all retries were not consumed: %d != %d\n", - rate->count, tx_count); - if (tx_count <= rate->count && tx_count && - arg->txed_rate != wfx_get_hw_rate(wdev, rate)) - dev_dbg(wdev->dev, "inconsistent tx_info rates: %d != %d\n", - arg->txed_rate, wfx_get_hw_rate(wdev, rate)); - if (tx_count > rate->count) { - tx_count -= rate->count; - } else if (!tx_count) { - rate->count = 0; - rate->idx = -1; - } else { - rate->count = tx_count; - tx_count = 0; - } - } - if (tx_count) - dev_dbg(wdev->dev, "%d more retries than expected\n", tx_count); -} - -void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg) -{ - struct ieee80211_tx_info *tx_info; - struct wfx_vif *wvif; - struct sk_buff *skb; - - skb = wfx_pending_get(wdev, arg->packet_id); - if (!skb) { - dev_warn(wdev->dev, "received unknown packet_id (%#.8x) from chip\n", - arg->packet_id); - return; - } - tx_info = IEEE80211_SKB_CB(skb); - wvif = wdev_to_wvif(wdev, ((struct hif_msg *)skb->data)->interface); - WARN_ON(!wvif); - if (!wvif) - return; - - // Note that wfx_pending_get_pkt_us_delay() get data from tx_info - _trace_tx_stats(arg, skb, wfx_pending_get_pkt_us_delay(wdev, skb)); - wfx_tx_fill_rates(wdev, tx_info, arg); - // From now, you can touch to tx_info->status, but do not touch to - // tx_priv anymore - // FIXME: use ieee80211_tx_info_clear_status() - memset(tx_info->rate_driver_data, 0, sizeof(tx_info->rate_driver_data)); - memset(tx_info->pad, 0, sizeof(tx_info->pad)); - - if (!arg->status) { - tx_info->status.tx_time = - le32_to_cpu(arg->media_delay) - - le32_to_cpu(arg->tx_queue_delay); - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; - else - tx_info->flags |= IEEE80211_TX_STAT_ACK; - } else if (arg->status == HIF_STATUS_TX_FAIL_REQUEUE) { - WARN(!arg->requeue, "incoherent status and result_flags"); - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { - wvif->after_dtim_tx_allowed = false; // DTIM period elapsed - schedule_work(&wvif->update_tim_work); - } - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - } - wfx_skb_dtor(wvif, skb); -} - -static void wfx_flush_vif(struct wfx_vif *wvif, u32 queues, - struct sk_buff_head *dropped) -{ - struct wfx_queue *queue; - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (!(BIT(i) & queues)) - continue; - queue = &wvif->tx_queue[i]; - if (dropped) - wfx_tx_queue_drop(wvif, queue, dropped); - } - if (wvif->wdev->chip_frozen) - return; - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (!(BIT(i) & queues)) - continue; - queue = &wvif->tx_queue[i]; - if (wait_event_timeout(wvif->wdev->tx_dequeue, - wfx_tx_queue_empty(wvif, queue), - msecs_to_jiffies(1000)) <= 0) - dev_warn(wvif->wdev->dev, - "frames queued while flushing tx queues?"); - } -} - -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) -{ - struct wfx_dev *wdev = hw->priv; - struct sk_buff_head dropped; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - skb_queue_head_init(&dropped); - if (vif) { - wvif = (struct wfx_vif *)vif->drv_priv; - wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); - } else { - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_flush_vif(wvif, queues, drop ? &dropped : NULL); - } - wfx_tx_flush(wdev); - if (wdev->chip_frozen) - wfx_pending_drop(wdev, &dropped); - while ((skb = skb_dequeue(&dropped)) != NULL) { - hif = (struct hif_msg *)skb->data; - wvif = wdev_to_wvif(wdev, hif->interface); - ieee80211_tx_info_clear_status(IEEE80211_SKB_CB(skb)); - wfx_skb_dtor(wvif, skb); - } -} diff --git a/drivers/staging/wfx/data_tx.h b/drivers/staging/wfx/data_tx.h deleted file mode 100644 index 46c9fff7a870..000000000000 --- a/drivers/staging/wfx/data_tx.h +++ /dev/null @@ -1,67 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Datapath implementation. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_DATA_TX_H -#define WFX_DATA_TX_H - -#include -#include - -#include "hif_api_cmd.h" -#include "hif_api_mib.h" - -struct wfx_tx_priv; -struct wfx_dev; -struct wfx_vif; - -struct tx_policy { - struct list_head link; - int usage_count; - u8 rates[12]; - bool uploaded; -}; - -struct tx_policy_cache { - struct tx_policy cache[HIF_TX_RETRY_POLICY_MAX]; - // FIXME: use a trees and drop hash from tx_policy - struct list_head used; - struct list_head free; - spinlock_t lock; -}; - -struct wfx_tx_priv { - ktime_t xmit_timestamp; -}; - -void wfx_tx_policy_init(struct wfx_vif *wvif); -void wfx_tx_policy_upload_work(struct work_struct *work); - -void wfx_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, - struct sk_buff *skb); -void wfx_tx_confirm_cb(struct wfx_dev *wdev, const struct hif_cnf_tx *arg); -void wfx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop); - -static inline struct wfx_tx_priv *wfx_skb_tx_priv(struct sk_buff *skb) -{ - struct ieee80211_tx_info *tx_info; - - if (!skb) - return NULL; - tx_info = IEEE80211_SKB_CB(skb); - return (struct wfx_tx_priv *)tx_info->rate_driver_data; -} - -static inline struct hif_req_tx *wfx_skb_txreq(struct sk_buff *skb) -{ - struct hif_msg *hif = (struct hif_msg *)skb->data; - struct hif_req_tx *req = (struct hif_req_tx *)hif->body; - - return req; -} - -#endif /* WFX_DATA_TX_H */ diff --git a/drivers/staging/wfx/debug.c b/drivers/staging/wfx/debug.c deleted file mode 100644 index eedada78c25f..000000000000 --- a/drivers/staging/wfx/debug.c +++ /dev/null @@ -1,359 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Debugfs interface. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include - -#include "debug.h" -#include "wfx.h" -#include "sta.h" -#include "main.h" -#include "hif_tx.h" -#include "hif_tx_mib.h" - -#define CREATE_TRACE_POINTS -#include "traces.h" - -static const struct trace_print_flags hif_msg_print_map[] = { - hif_msg_list, -}; - -static const struct trace_print_flags hif_mib_print_map[] = { - hif_mib_list, -}; - -static const struct trace_print_flags wfx_reg_print_map[] = { - wfx_reg_list, -}; - -static const char *get_symbol(unsigned long val, - const struct trace_print_flags *symbol_array) -{ - int i; - - for (i = 0; symbol_array[i].mask != -1; i++) { - if (val == symbol_array[i].mask) - return symbol_array[i].name; - } - - return "unknown"; -} - -const char *get_hif_name(unsigned long id) -{ - return get_symbol(id, hif_msg_print_map); -} - -const char *get_mib_name(unsigned long id) -{ - return get_symbol(id, hif_mib_print_map); -} - -const char *get_reg_name(unsigned long id) -{ - return get_symbol(id, wfx_reg_print_map); -} - -static int wfx_counters_show(struct seq_file *seq, void *v) -{ - int ret, i; - struct wfx_dev *wdev = seq->private; - struct hif_mib_extended_count_table counters[3]; - - for (i = 0; i < ARRAY_SIZE(counters); i++) { - ret = hif_get_counters_table(wdev, i, counters + i); - if (ret < 0) - return ret; - if (ret > 0) - return -EIO; - } - - seq_printf(seq, "%-24s %12s %12s %12s\n", - "", "global", "iface 0", "iface 1"); - -#define PUT_COUNTER(name) \ - seq_printf(seq, "%-24s %12d %12d %12d\n", #name, \ - le32_to_cpu(counters[2].count_##name), \ - le32_to_cpu(counters[0].count_##name), \ - le32_to_cpu(counters[1].count_##name)) - - PUT_COUNTER(tx_packets); - PUT_COUNTER(tx_multicast_frames); - PUT_COUNTER(tx_frames_success); - PUT_COUNTER(tx_frame_failures); - PUT_COUNTER(tx_frames_retried); - PUT_COUNTER(tx_frames_multi_retried); - - PUT_COUNTER(rts_success); - PUT_COUNTER(rts_failures); - PUT_COUNTER(ack_failures); - - PUT_COUNTER(rx_packets); - PUT_COUNTER(rx_frames_success); - PUT_COUNTER(rx_packet_errors); - PUT_COUNTER(plcp_errors); - PUT_COUNTER(fcs_errors); - PUT_COUNTER(rx_decryption_failures); - PUT_COUNTER(rx_mic_failures); - PUT_COUNTER(rx_no_key_failures); - PUT_COUNTER(rx_frame_duplicates); - PUT_COUNTER(rx_multicast_frames); - PUT_COUNTER(rx_cmacicv_errors); - PUT_COUNTER(rx_cmac_replays); - PUT_COUNTER(rx_mgmt_ccmp_replays); - - PUT_COUNTER(rx_beacon); - PUT_COUNTER(miss_beacon); - -#undef PUT_COUNTER - - for (i = 0; i < ARRAY_SIZE(counters[0].reserved); i++) - seq_printf(seq, "reserved[%02d]%12s %12d %12d %12d\n", i, "", - le32_to_cpu(counters[2].reserved[i]), - le32_to_cpu(counters[0].reserved[i]), - le32_to_cpu(counters[1].reserved[i])); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_counters); - -static const char * const channel_names[] = { - [0] = "1M", - [1] = "2M", - [2] = "5.5M", - [3] = "11M", - /* Entries 4 and 5 does not exist */ - [6] = "6M", - [7] = "9M", - [8] = "12M", - [9] = "18M", - [10] = "24M", - [11] = "36M", - [12] = "48M", - [13] = "54M", - [14] = "MCS0", - [15] = "MCS1", - [16] = "MCS2", - [17] = "MCS3", - [18] = "MCS4", - [19] = "MCS5", - [20] = "MCS6", - [21] = "MCS7", -}; - -static int wfx_rx_stats_show(struct seq_file *seq, void *v) -{ - struct wfx_dev *wdev = seq->private; - struct hif_rx_stats *st = &wdev->rx_stats; - int i; - - mutex_lock(&wdev->rx_stats_lock); - seq_printf(seq, "Timestamp: %dus\n", st->date); - seq_printf(seq, "Low power clock: frequency %uHz, external %s\n", - le32_to_cpu(st->pwr_clk_freq), - st->is_ext_pwr_clk ? "yes" : "no"); - seq_printf(seq, - "Num. of frames: %d, PER (x10e4): %d, Throughput: %dKbps/s\n", - st->nb_rx_frame, st->per_total, st->throughput); - seq_puts(seq, " Num. of PER RSSI SNR CFO\n"); - seq_puts(seq, " frames (x10e4) (dBm) (dB) (kHz)\n"); - for (i = 0; i < ARRAY_SIZE(channel_names); i++) { - if (channel_names[i]) - seq_printf(seq, "%5s %8d %8d %8d %8d %8d\n", - channel_names[i], - le32_to_cpu(st->nb_rx_by_rate[i]), - le16_to_cpu(st->per[i]), - (s16)le16_to_cpu(st->rssi[i]) / 100, - (s16)le16_to_cpu(st->snr[i]) / 100, - (s16)le16_to_cpu(st->cfo[i])); - } - mutex_unlock(&wdev->rx_stats_lock); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_rx_stats); - -static int wfx_tx_power_loop_show(struct seq_file *seq, void *v) -{ - struct wfx_dev *wdev = seq->private; - struct hif_tx_power_loop_info *st = &wdev->tx_power_loop_info; - int tmp; - - mutex_lock(&wdev->tx_power_loop_info_lock); - tmp = le16_to_cpu(st->tx_gain_dig); - seq_printf(seq, "Tx gain digital: %d\n", tmp); - tmp = le16_to_cpu(st->tx_gain_pa); - seq_printf(seq, "Tx gain PA: %d\n", tmp); - tmp = (s16)le16_to_cpu(st->target_pout); - seq_printf(seq, "Target Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); - tmp = (s16)le16_to_cpu(st->p_estimation); - seq_printf(seq, "FEM Pout: %d.%02d dBm\n", tmp / 4, (tmp % 4) * 25); - tmp = le16_to_cpu(st->vpdet); - seq_printf(seq, "Vpdet: %d mV\n", tmp); - seq_printf(seq, "Measure index: %d\n", st->measurement_index); - mutex_unlock(&wdev->tx_power_loop_info_lock); - - return 0; -} -DEFINE_SHOW_ATTRIBUTE(wfx_tx_power_loop); - -static ssize_t wfx_send_pds_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct wfx_dev *wdev = file->private_data; - char *buf; - int ret; - - if (*ppos != 0) { - dev_dbg(wdev->dev, "PDS data must be written in one transaction"); - return -EBUSY; - } - buf = memdup_user(user_buf, count); - if (IS_ERR(buf)) - return PTR_ERR(buf); - *ppos = *ppos + count; - ret = wfx_send_pds(wdev, buf, count); - kfree(buf); - if (ret < 0) - return ret; - return count; -} - -static const struct file_operations wfx_send_pds_fops = { - .open = simple_open, - .write = wfx_send_pds_write, -}; - -struct dbgfs_hif_msg { - struct wfx_dev *wdev; - struct completion complete; - u8 reply[1024]; - int ret; -}; - -static ssize_t wfx_send_hif_msg_write(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dbgfs_hif_msg *context = file->private_data; - struct wfx_dev *wdev = context->wdev; - struct hif_msg *request; - - if (completion_done(&context->complete)) { - dev_dbg(wdev->dev, "read previous result before start a new one\n"); - return -EBUSY; - } - if (count < sizeof(struct hif_msg)) - return -EINVAL; - - // wfx_cmd_send() checks that reply buffer is wide enough, but does not - // return precise length read. User have to know how many bytes should - // be read. Filling reply buffer with a memory pattern may help user. - memset(context->reply, 0xFF, sizeof(context->reply)); - request = memdup_user(user_buf, count); - if (IS_ERR(request)) - return PTR_ERR(request); - if (le16_to_cpu(request->len) != count) { - kfree(request); - return -EINVAL; - } - context->ret = wfx_cmd_send(wdev, request, context->reply, - sizeof(context->reply), false); - - kfree(request); - complete(&context->complete); - return count; -} - -static ssize_t wfx_send_hif_msg_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct dbgfs_hif_msg *context = file->private_data; - int ret; - - if (count > sizeof(context->reply)) - return -EINVAL; - ret = wait_for_completion_interruptible(&context->complete); - if (ret) - return ret; - if (context->ret < 0) - return context->ret; - // Be careful, write() is waiting for a full message while read() - // only returns a payload - if (copy_to_user(user_buf, context->reply, count)) - return -EFAULT; - - return count; -} - -static int wfx_send_hif_msg_open(struct inode *inode, struct file *file) -{ - struct dbgfs_hif_msg *context = kzalloc(sizeof(*context), GFP_KERNEL); - - if (!context) - return -ENOMEM; - context->wdev = inode->i_private; - init_completion(&context->complete); - file->private_data = context; - return 0; -} - -static int wfx_send_hif_msg_release(struct inode *inode, struct file *file) -{ - struct dbgfs_hif_msg *context = file->private_data; - - kfree(context); - return 0; -} - -static const struct file_operations wfx_send_hif_msg_fops = { - .open = wfx_send_hif_msg_open, - .release = wfx_send_hif_msg_release, - .write = wfx_send_hif_msg_write, - .read = wfx_send_hif_msg_read, -}; - -static int wfx_ps_timeout_set(void *data, u64 val) -{ - struct wfx_dev *wdev = (struct wfx_dev *)data; - struct wfx_vif *wvif; - - wdev->force_ps_timeout = val; - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); - return 0; -} - -static int wfx_ps_timeout_get(void *data, u64 *val) -{ - struct wfx_dev *wdev = (struct wfx_dev *)data; - - *val = wdev->force_ps_timeout; - return 0; -} - -DEFINE_DEBUGFS_ATTRIBUTE(wfx_ps_timeout_fops, wfx_ps_timeout_get, wfx_ps_timeout_set, "%lld\n"); - -int wfx_debug_init(struct wfx_dev *wdev) -{ - struct dentry *d; - - d = debugfs_create_dir("wfx", wdev->hw->wiphy->debugfsdir); - debugfs_create_file("counters", 0444, d, wdev, &wfx_counters_fops); - debugfs_create_file("rx_stats", 0444, d, wdev, &wfx_rx_stats_fops); - debugfs_create_file("tx_power_loop", 0444, d, wdev, - &wfx_tx_power_loop_fops); - debugfs_create_file("send_pds", 0200, d, wdev, &wfx_send_pds_fops); - debugfs_create_file("send_hif_msg", 0600, d, wdev, - &wfx_send_hif_msg_fops); - debugfs_create_file("ps_timeout", 0600, d, wdev, &wfx_ps_timeout_fops); - - return 0; -} diff --git a/drivers/staging/wfx/debug.h b/drivers/staging/wfx/debug.h deleted file mode 100644 index 6f2f84d64c9e..000000000000 --- a/drivers/staging/wfx/debug.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Debugfs interface. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2011, ST-Ericsson - */ -#ifndef WFX_DEBUG_H -#define WFX_DEBUG_H - -struct wfx_dev; - -int wfx_debug_init(struct wfx_dev *wdev); - -const char *get_hif_name(unsigned long id); -const char *get_mib_name(unsigned long id); -const char *get_reg_name(unsigned long id); - -#endif /* WFX_DEBUG_H */ diff --git a/drivers/staging/wfx/fwio.c b/drivers/staging/wfx/fwio.c deleted file mode 100644 index 1b8aec02d169..000000000000 --- a/drivers/staging/wfx/fwio.c +++ /dev/null @@ -1,405 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Firmware loading. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include -#include - -#include "fwio.h" -#include "wfx.h" -#include "hwio.h" - -// Addresses below are in SRAM area -#define WFX_DNLD_FIFO 0x09004000 -#define DNLD_BLOCK_SIZE 0x0400 -#define DNLD_FIFO_SIZE 0x8000 // (32 * DNLD_BLOCK_SIZE) -// Download Control Area (DCA) -#define WFX_DCA_IMAGE_SIZE 0x0900C000 -#define WFX_DCA_PUT 0x0900C004 -#define WFX_DCA_GET 0x0900C008 -#define WFX_DCA_HOST_STATUS 0x0900C00C -#define HOST_READY 0x87654321 -#define HOST_INFO_READ 0xA753BD99 -#define HOST_UPLOAD_PENDING 0xABCDDCBA -#define HOST_UPLOAD_COMPLETE 0xD4C64A99 -#define HOST_OK_TO_JUMP 0x174FC882 -#define WFX_DCA_NCP_STATUS 0x0900C010 -#define NCP_NOT_READY 0x12345678 -#define NCP_READY 0x87654321 -#define NCP_INFO_READY 0xBD53EF99 -#define NCP_DOWNLOAD_PENDING 0xABCDDCBA -#define NCP_DOWNLOAD_COMPLETE 0xCAFEFECA -#define NCP_AUTH_OK 0xD4C64A99 -#define NCP_AUTH_FAIL 0x174FC882 -#define NCP_PUB_KEY_RDY 0x7AB41D19 -#define WFX_DCA_FW_SIGNATURE 0x0900C014 -#define FW_SIGNATURE_SIZE 0x40 -#define WFX_DCA_FW_HASH 0x0900C054 -#define FW_HASH_SIZE 0x08 -#define WFX_DCA_FW_VERSION 0x0900C05C -#define FW_VERSION_SIZE 0x04 -#define WFX_DCA_RESERVED 0x0900C060 -#define DCA_RESERVED_SIZE 0x20 -#define WFX_STATUS_INFO 0x0900C080 -#define WFX_BOOTLOADER_LABEL 0x0900C084 -#define BOOTLOADER_LABEL_SIZE 0x3C -#define WFX_PTE_INFO 0x0900C0C0 -#define PTE_INFO_KEYSET_IDX 0x0D -#define PTE_INFO_SIZE 0x10 -#define WFX_ERR_INFO 0x0900C0D0 -#define ERR_INVALID_SEC_TYPE 0x05 -#define ERR_SIG_VERIF_FAILED 0x0F -#define ERR_AES_CTRL_KEY 0x10 -#define ERR_ECC_PUB_KEY 0x11 -#define ERR_MAC_KEY 0x18 - -#define DCA_TIMEOUT 50 // milliseconds -#define WAKEUP_TIMEOUT 200 // milliseconds - -static const char * const fwio_errors[] = { - [ERR_INVALID_SEC_TYPE] = "Invalid section type or wrong encryption", - [ERR_SIG_VERIF_FAILED] = "Signature verification failed", - [ERR_AES_CTRL_KEY] = "AES control key not initialized", - [ERR_ECC_PUB_KEY] = "ECC public key not initialized", - [ERR_MAC_KEY] = "MAC key not initialized", -}; - -/* - * request_firmware() allocate data using vmalloc(). It is not compatible with - * underlying hardware that use DMA. Function below detect this case and - * allocate a bounce buffer if necessary. - * - * Notice that, in doubt, you can enable CONFIG_DEBUG_SG to ask kernel to - * detect this problem at runtime (else, kernel silently fail). - * - * NOTE: it may also be possible to use 'pages' from struct firmware and avoid - * bounce buffer - */ -static int sram_write_dma_safe(struct wfx_dev *wdev, u32 addr, const u8 *buf, - size_t len) -{ - int ret; - const u8 *tmp; - - if (!virt_addr_valid(buf)) { - tmp = kmemdup(buf, len, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - } else { - tmp = buf; - } - ret = sram_buf_write(wdev, addr, tmp, len); - if (tmp != buf) - kfree(tmp); - return ret; -} - -static int get_firmware(struct wfx_dev *wdev, u32 keyset_chip, - const struct firmware **fw, int *file_offset) -{ - int keyset_file; - char filename[256]; - const char *data; - int ret; - - snprintf(filename, sizeof(filename), "%s_%02X.sec", - wdev->pdata.file_fw, keyset_chip); - ret = firmware_request_nowarn(fw, filename, wdev->dev); - if (ret) { - dev_info(wdev->dev, "can't load %s, falling back to %s.sec\n", - filename, wdev->pdata.file_fw); - snprintf(filename, sizeof(filename), "%s.sec", - wdev->pdata.file_fw); - ret = request_firmware(fw, filename, wdev->dev); - if (ret) { - dev_err(wdev->dev, "can't load %s\n", filename); - *fw = NULL; - return ret; - } - } - - data = (*fw)->data; - if (memcmp(data, "KEYSET", 6) != 0) { - // Legacy firmware format - *file_offset = 0; - keyset_file = 0x90; - } else { - *file_offset = 8; - keyset_file = (hex_to_bin(data[6]) * 16) | hex_to_bin(data[7]); - if (keyset_file < 0) { - dev_err(wdev->dev, "%s corrupted\n", filename); - release_firmware(*fw); - *fw = NULL; - return -EINVAL; - } - } - if (keyset_file != keyset_chip) { - dev_err(wdev->dev, "firmware keyset is incompatible with chip (file: 0x%02X, chip: 0x%02X)\n", - keyset_file, keyset_chip); - release_firmware(*fw); - *fw = NULL; - return -ENODEV; - } - wdev->keyset = keyset_file; - return 0; -} - -static int wait_ncp_status(struct wfx_dev *wdev, u32 status) -{ - ktime_t now, start; - u32 reg; - int ret; - - start = ktime_get(); - for (;;) { - ret = sram_reg_read(wdev, WFX_DCA_NCP_STATUS, ®); - if (ret < 0) - return -EIO; - now = ktime_get(); - if (reg == status) - break; - if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) - return -ETIMEDOUT; - } - if (ktime_compare(now, start)) - dev_dbg(wdev->dev, "chip answer after %lldus\n", - ktime_us_delta(now, start)); - else - dev_dbg(wdev->dev, "chip answer immediately\n"); - return 0; -} - -static int upload_firmware(struct wfx_dev *wdev, const u8 *data, size_t len) -{ - int ret; - u32 offs, bytes_done = 0; - ktime_t now, start; - - if (len % DNLD_BLOCK_SIZE) { - dev_err(wdev->dev, "firmware size is not aligned. Buffer overrun will occur\n"); - return -EIO; - } - offs = 0; - while (offs < len) { - start = ktime_get(); - for (;;) { - now = ktime_get(); - if (offs + DNLD_BLOCK_SIZE - bytes_done < DNLD_FIFO_SIZE) - break; - if (ktime_after(now, ktime_add_ms(start, DCA_TIMEOUT))) - return -ETIMEDOUT; - ret = sram_reg_read(wdev, WFX_DCA_GET, &bytes_done); - if (ret < 0) - return ret; - } - if (ktime_compare(now, start)) - dev_dbg(wdev->dev, "answer after %lldus\n", - ktime_us_delta(now, start)); - - ret = sram_write_dma_safe(wdev, WFX_DNLD_FIFO + - (offs % DNLD_FIFO_SIZE), - data + offs, DNLD_BLOCK_SIZE); - if (ret < 0) - return ret; - - // WFx seems to not support writing 0 in this register during - // first loop - offs += DNLD_BLOCK_SIZE; - ret = sram_reg_write(wdev, WFX_DCA_PUT, offs); - if (ret < 0) - return ret; - } - return 0; -} - -static void print_boot_status(struct wfx_dev *wdev) -{ - u32 reg; - - sram_reg_read(wdev, WFX_STATUS_INFO, ®); - if (reg == 0x12345678) - return; - sram_reg_read(wdev, WFX_ERR_INFO, ®); - if (reg < ARRAY_SIZE(fwio_errors) && fwio_errors[reg]) - dev_info(wdev->dev, "secure boot: %s\n", fwio_errors[reg]); - else - dev_info(wdev->dev, "secure boot: Error %#02x\n", reg); -} - -static int load_firmware_secure(struct wfx_dev *wdev) -{ - const struct firmware *fw = NULL; - int header_size; - int fw_offset; - ktime_t start; - u8 *buf; - int ret; - - BUILD_BUG_ON(PTE_INFO_SIZE > BOOTLOADER_LABEL_SIZE); - buf = kmalloc(BOOTLOADER_LABEL_SIZE + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_READY); - ret = wait_ncp_status(wdev, NCP_INFO_READY); - if (ret) - goto error; - - sram_buf_read(wdev, WFX_BOOTLOADER_LABEL, buf, BOOTLOADER_LABEL_SIZE); - buf[BOOTLOADER_LABEL_SIZE] = 0; - dev_dbg(wdev->dev, "bootloader: \"%s\"\n", buf); - - sram_buf_read(wdev, WFX_PTE_INFO, buf, PTE_INFO_SIZE); - ret = get_firmware(wdev, buf[PTE_INFO_KEYSET_IDX], &fw, &fw_offset); - if (ret) - goto error; - header_size = fw_offset + FW_SIGNATURE_SIZE + FW_HASH_SIZE; - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_INFO_READ); - ret = wait_ncp_status(wdev, NCP_READY); - if (ret) - goto error; - - sram_reg_write(wdev, WFX_DNLD_FIFO, 0xFFFFFFFF); // Fifo init - sram_write_dma_safe(wdev, WFX_DCA_FW_VERSION, "\x01\x00\x00\x00", - FW_VERSION_SIZE); - sram_write_dma_safe(wdev, WFX_DCA_FW_SIGNATURE, fw->data + fw_offset, - FW_SIGNATURE_SIZE); - sram_write_dma_safe(wdev, WFX_DCA_FW_HASH, - fw->data + fw_offset + FW_SIGNATURE_SIZE, - FW_HASH_SIZE); - sram_reg_write(wdev, WFX_DCA_IMAGE_SIZE, fw->size - header_size); - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_PENDING); - ret = wait_ncp_status(wdev, NCP_DOWNLOAD_PENDING); - if (ret) - goto error; - - start = ktime_get(); - ret = upload_firmware(wdev, fw->data + header_size, - fw->size - header_size); - if (ret) - goto error; - dev_dbg(wdev->dev, "firmware load after %lldus\n", - ktime_us_delta(ktime_get(), start)); - - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_UPLOAD_COMPLETE); - ret = wait_ncp_status(wdev, NCP_AUTH_OK); - // Legacy ROM support - if (ret < 0) - ret = wait_ncp_status(wdev, NCP_PUB_KEY_RDY); - if (ret < 0) - goto error; - sram_reg_write(wdev, WFX_DCA_HOST_STATUS, HOST_OK_TO_JUMP); - -error: - kfree(buf); - if (fw) - release_firmware(fw); - if (ret) - print_boot_status(wdev); - return ret; -} - -static int init_gpr(struct wfx_dev *wdev) -{ - int ret, i; - static const struct { - int index; - u32 value; - } gpr_init[] = { - { 0x07, 0x208775 }, - { 0x08, 0x2EC020 }, - { 0x09, 0x3C3C3C }, - { 0x0B, 0x322C44 }, - { 0x0C, 0xA06497 }, - }; - - for (i = 0; i < ARRAY_SIZE(gpr_init); i++) { - ret = igpr_reg_write(wdev, gpr_init[i].index, - gpr_init[i].value); - if (ret < 0) - return ret; - dev_dbg(wdev->dev, " index %02x: %08x\n", - gpr_init[i].index, gpr_init[i].value); - } - return 0; -} - -int wfx_init_device(struct wfx_dev *wdev) -{ - int ret; - int hw_revision, hw_type; - int wakeup_timeout = 50; // ms - ktime_t now, start; - u32 reg; - - reg = CFG_DIRECT_ACCESS_MODE | CFG_CPU_RESET | CFG_BYTE_ORDER_ABCD; - if (wdev->pdata.use_rising_clk) - reg |= CFG_CLK_RISE_EDGE; - ret = config_reg_write(wdev, reg); - if (ret < 0) { - dev_err(wdev->dev, "bus returned an error during first write access. Host configuration error?\n"); - return -EIO; - } - - ret = config_reg_read(wdev, ®); - if (ret < 0) { - dev_err(wdev->dev, "bus returned an error during first read access. Bus configuration error?\n"); - return -EIO; - } - if (reg == 0 || reg == ~0) { - dev_err(wdev->dev, "chip mute. Bus configuration error or chip wasn't reset?\n"); - return -EIO; - } - dev_dbg(wdev->dev, "initial config register value: %08x\n", reg); - - hw_revision = FIELD_GET(CFG_DEVICE_ID_MAJOR, reg); - if (hw_revision == 0) { - dev_err(wdev->dev, "bad hardware revision number: %d\n", - hw_revision); - return -ENODEV; - } - hw_type = FIELD_GET(CFG_DEVICE_ID_TYPE, reg); - if (hw_type == 1) { - dev_notice(wdev->dev, "development hardware detected\n"); - wakeup_timeout = 2000; - } - - ret = init_gpr(wdev); - if (ret < 0) - return ret; - - ret = control_reg_write(wdev, CTRL_WLAN_WAKEUP); - if (ret < 0) - return -EIO; - start = ktime_get(); - for (;;) { - ret = control_reg_read(wdev, ®); - now = ktime_get(); - if (reg & CTRL_WLAN_READY) - break; - if (ktime_after(now, ktime_add_ms(start, wakeup_timeout))) { - dev_err(wdev->dev, "chip didn't wake up. Chip wasn't reset?\n"); - return -ETIMEDOUT; - } - } - dev_dbg(wdev->dev, "chip wake up after %lldus\n", - ktime_us_delta(now, start)); - - ret = config_reg_write_bits(wdev, CFG_CPU_RESET, 0); - if (ret < 0) - return ret; - ret = load_firmware_secure(wdev); - if (ret < 0) - return ret; - return config_reg_write_bits(wdev, - CFG_DIRECT_ACCESS_MODE | - CFG_IRQ_ENABLE_DATA | - CFG_IRQ_ENABLE_WRDY, - CFG_IRQ_ENABLE_DATA); -} diff --git a/drivers/staging/wfx/fwio.h b/drivers/staging/wfx/fwio.h deleted file mode 100644 index 6028f92503fe..000000000000 --- a/drivers/staging/wfx/fwio.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Firmware loading. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_FWIO_H -#define WFX_FWIO_H - -struct wfx_dev; - -int wfx_init_device(struct wfx_dev *wdev); - -#endif /* WFX_FWIO_H */ diff --git a/drivers/staging/wfx/hif_api_cmd.h b/drivers/staging/wfx/hif_api_cmd.h deleted file mode 100644 index 11bc1a58edae..000000000000 --- a/drivers/staging/wfx/hif_api_cmd.h +++ /dev/null @@ -1,553 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_CMD_H -#define WFX_HIF_API_CMD_H - -#include - -#include "hif_api_general.h" - -enum hif_requests_ids { - HIF_REQ_ID_RESET = 0x0a, - HIF_REQ_ID_READ_MIB = 0x05, - HIF_REQ_ID_WRITE_MIB = 0x06, - HIF_REQ_ID_START_SCAN = 0x07, - HIF_REQ_ID_STOP_SCAN = 0x08, - HIF_REQ_ID_TX = 0x04, - HIF_REQ_ID_JOIN = 0x0b, - HIF_REQ_ID_SET_PM_MODE = 0x10, - HIF_REQ_ID_SET_BSS_PARAMS = 0x11, - HIF_REQ_ID_ADD_KEY = 0x0c, - HIF_REQ_ID_REMOVE_KEY = 0x0d, - HIF_REQ_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_REQ_ID_START = 0x17, - HIF_REQ_ID_BEACON_TRANSMIT = 0x18, - HIF_REQ_ID_UPDATE_IE = 0x1b, - HIF_REQ_ID_MAP_LINK = 0x1c, -}; - -enum hif_confirmations_ids { - HIF_CNF_ID_RESET = 0x0a, - HIF_CNF_ID_READ_MIB = 0x05, - HIF_CNF_ID_WRITE_MIB = 0x06, - HIF_CNF_ID_START_SCAN = 0x07, - HIF_CNF_ID_STOP_SCAN = 0x08, - HIF_CNF_ID_TX = 0x04, - HIF_CNF_ID_MULTI_TRANSMIT = 0x1e, - HIF_CNF_ID_JOIN = 0x0b, - HIF_CNF_ID_SET_PM_MODE = 0x10, - HIF_CNF_ID_SET_BSS_PARAMS = 0x11, - HIF_CNF_ID_ADD_KEY = 0x0c, - HIF_CNF_ID_REMOVE_KEY = 0x0d, - HIF_CNF_ID_EDCA_QUEUE_PARAMS = 0x13, - HIF_CNF_ID_START = 0x17, - HIF_CNF_ID_BEACON_TRANSMIT = 0x18, - HIF_CNF_ID_UPDATE_IE = 0x1b, - HIF_CNF_ID_MAP_LINK = 0x1c, -}; - -enum hif_indications_ids { - HIF_IND_ID_RX = 0x84, - HIF_IND_ID_SCAN_CMPL = 0x86, - HIF_IND_ID_JOIN_COMPLETE = 0x8f, - HIF_IND_ID_SET_PM_MODE_CMPL = 0x89, - HIF_IND_ID_SUSPEND_RESUME_TX = 0x8c, - HIF_IND_ID_EVENT = 0x85 -}; - -struct hif_req_reset { - u8 reset_stat:1; - u8 reset_all_int:1; - u8 reserved1:6; - u8 reserved2[3]; -} __packed; - -struct hif_cnf_reset { - __le32 status; -} __packed; - -struct hif_req_read_mib { - __le16 mib_id; - __le16 reserved; -} __packed; - -struct hif_cnf_read_mib { - __le32 status; - __le16 mib_id; - __le16 length; - u8 mib_data[]; -} __packed; - -struct hif_req_write_mib { - __le16 mib_id; - __le16 length; - u8 mib_data[]; -} __packed; - -struct hif_cnf_write_mib { - __le32 status; -} __packed; - -struct hif_req_update_ie { - u8 beacon:1; - u8 probe_resp:1; - u8 probe_req:1; - u8 reserved1:5; - u8 reserved2; - __le16 num_ies; - struct element ie[]; -} __packed; - -struct hif_cnf_update_ie { - __le32 status; -} __packed; - -struct hif_ssid_def { - __le32 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; -} __packed; - -#define HIF_API_MAX_NB_SSIDS 2 -#define HIF_API_MAX_NB_CHANNELS 14 - -struct hif_req_start_scan_alt { - u8 band; - u8 maintain_current_bss:1; - u8 periodic:1; - u8 reserved1:6; - u8 disallow_ps:1; - u8 reserved2:1; - u8 short_preamble:1; - u8 reserved3:5; - u8 max_transmit_rate; - __le16 periodic_interval; - u8 reserved4; - s8 periodic_rssi_thr; - u8 num_of_probe_requests; - u8 probe_delay; - u8 num_of_ssids; - u8 num_of_channels; - __le32 min_channel_time; - __le32 max_channel_time; - __le32 tx_power_level; // signed value - struct hif_ssid_def ssid_def[HIF_API_MAX_NB_SSIDS]; - u8 channel_list[]; -} __packed; - -struct hif_cnf_start_scan { - __le32 status; -} __packed; - -struct hif_cnf_stop_scan { - __le32 status; -} __packed; - -enum hif_pm_mode_status { - HIF_PM_MODE_ACTIVE = 0x0, - HIF_PM_MODE_PS = 0x1, - HIF_PM_MODE_UNDETERMINED = 0x2 -}; - -struct hif_ind_scan_cmpl { - __le32 status; - u8 pm_mode; - u8 num_channels_completed; - __le16 reserved; -} __packed; - -enum hif_queue_id { - HIF_QUEUE_ID_BACKGROUND = 0x0, - HIF_QUEUE_ID_BESTEFFORT = 0x1, - HIF_QUEUE_ID_VIDEO = 0x2, - HIF_QUEUE_ID_VOICE = 0x3 -}; - -enum hif_frame_format { - HIF_FRAME_FORMAT_NON_HT = 0x0, - HIF_FRAME_FORMAT_MIXED_FORMAT_HT = 0x1, - HIF_FRAME_FORMAT_GF_HT_11N = 0x2 -}; - -struct hif_req_tx { - // packet_id is not interpreted by the device, so it is not necessary to - // declare it little endian - u32 packet_id; - u8 max_tx_rate; - u8 queue_id:2; - u8 peer_sta_id:4; - u8 reserved1:2; - u8 more:1; - u8 fc_offset:3; - u8 after_dtim:1; - u8 reserved2:3; - u8 start_exp:1; - u8 reserved3:3; - u8 retry_policy_index:4; - __le32 reserved4; - __le32 expire_time; - u8 frame_format:4; - u8 fec_coding:1; - u8 short_gi:1; - u8 reserved5:1; - u8 stbc:1; - u8 reserved6; - u8 aggregation:1; - u8 reserved7:7; - u8 reserved8; - u8 frame[]; -} __packed; - -enum hif_qos_ackplcy { - HIF_QOS_ACKPLCY_NORMAL = 0x0, - HIF_QOS_ACKPLCY_TXNOACK = 0x1, - HIF_QOS_ACKPLCY_NOEXPACK = 0x2, - HIF_QOS_ACKPLCY_BLCKACK = 0x3 -}; - -struct hif_cnf_tx { - __le32 status; - // packet_id is copied from struct hif_req_tx without been interpreted - // by the device, so it is not necessary to declare it little endian - u32 packet_id; - u8 txed_rate; - u8 ack_failures; - u8 aggr:1; - u8 requeue:1; - u8 ack_policy:2; - u8 txop_limit:1; - u8 reserved1:3; - u8 reserved2; - __le32 media_delay; - __le32 tx_queue_delay; -} __packed; - -struct hif_cnf_multi_transmit { - u8 num_tx_confs; - u8 reserved[3]; - struct hif_cnf_tx tx_conf_payload[]; -} __packed; - -enum hif_ri_flags_encrypt { - HIF_RI_FLAGS_UNENCRYPTED = 0x0, - HIF_RI_FLAGS_WEP_ENCRYPTED = 0x1, - HIF_RI_FLAGS_TKIP_ENCRYPTED = 0x2, - HIF_RI_FLAGS_AES_ENCRYPTED = 0x3, - HIF_RI_FLAGS_WAPI_ENCRYPTED = 0x4 -}; - -struct hif_ind_rx { - __le32 status; - u8 channel_number; - u8 reserved1; - u8 rxed_rate; - u8 rcpi_rssi; - u8 encryp:3; - u8 in_aggr:1; - u8 first_aggr:1; - u8 last_aggr:1; - u8 defrag:1; - u8 beacon:1; - u8 tim:1; - u8 bitmap:1; - u8 match_ssid:1; - u8 match_bssid:1; - u8 more:1; - u8 reserved2:1; - u8 ht:1; - u8 stbc:1; - u8 match_uc_addr:1; - u8 match_mc_addr:1; - u8 match_bc_addr:1; - u8 key_type:1; - u8 key_index:4; - u8 reserved3:1; - u8 peer_sta_id:4; - u8 reserved4:2; - u8 reserved5:1; - u8 frame[]; -} __packed; - -struct hif_req_edca_queue_params { - u8 queue_id; - u8 reserved1; - u8 aifsn; - u8 reserved2; - __le16 cw_min; - __le16 cw_max; - __le16 tx_op_limit; - __le16 allowed_medium_time; - __le32 reserved3; -} __packed; - -struct hif_cnf_edca_queue_params { - __le32 status; -} __packed; - -struct hif_req_join { - u8 infrastructure_bss_mode:1; - u8 reserved1:7; - u8 band; - u8 channel_number; - u8 reserved2; - u8 bssid[ETH_ALEN]; - __le16 atim_window; - u8 short_preamble:1; - u8 reserved3:7; - u8 probe_for_join; - u8 reserved4; - u8 reserved5:2; - u8 force_no_beacon:1; - u8 force_with_ind:1; - u8 reserved6:4; - __le32 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - __le32 beacon_interval; - __le32 basic_rate_set; -} __packed; - -struct hif_cnf_join { - __le32 status; -} __packed; - -struct hif_ind_join_complete { - __le32 status; -} __packed; - -struct hif_req_set_bss_params { - u8 lost_count_only:1; - u8 reserved:7; - u8 beacon_lost_count; - __le16 aid; - __le32 operational_rate_set; -} __packed; - -struct hif_cnf_set_bss_params { - __le32 status; -} __packed; - -struct hif_req_set_pm_mode { - u8 enter_psm:1; - u8 reserved:6; - u8 fast_psm:1; - u8 fast_psm_idle_period; - u8 ap_psm_change_period; - u8 min_auto_ps_poll_period; -} __packed; - -struct hif_cnf_set_pm_mode { - __le32 status; -} __packed; - -struct hif_ind_set_pm_mode_cmpl { - __le32 status; - u8 pm_mode; - u8 reserved[3]; -} __packed; - -struct hif_req_start { - u8 mode; - u8 band; - u8 channel_number; - u8 reserved1; - __le32 reserved2; - __le32 beacon_interval; - u8 dtim_period; - u8 short_preamble:1; - u8 reserved3:7; - u8 reserved4; - u8 ssid_length; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - __le32 basic_rate_set; -} __packed; - -struct hif_cnf_start { - __le32 status; -} __packed; - -struct hif_req_beacon_transmit { - u8 enable_beaconing; - u8 reserved[3]; -} __packed; - -struct hif_cnf_beacon_transmit { - __le32 status; -} __packed; - -#define HIF_LINK_ID_MAX 14 -#define HIF_LINK_ID_NOT_ASSOCIATED (HIF_LINK_ID_MAX + 1) - -struct hif_req_map_link { - u8 mac_addr[ETH_ALEN]; - u8 unmap:1; - u8 mfpc:1; - u8 reserved:6; - u8 peer_sta_id; -} __packed; - -struct hif_cnf_map_link { - __le32 status; -} __packed; - -struct hif_ind_suspend_resume_tx { - u8 resume:1; - u8 reserved1:2; - u8 bc_mc_only:1; - u8 reserved2:4; - u8 reserved3; - __le16 peer_sta_set; -} __packed; - - -#define MAX_KEY_ENTRIES 24 -#define HIF_API_WEP_KEY_DATA_SIZE 16 -#define HIF_API_TKIP_KEY_DATA_SIZE 16 -#define HIF_API_RX_MIC_KEY_SIZE 8 -#define HIF_API_TX_MIC_KEY_SIZE 8 -#define HIF_API_AES_KEY_DATA_SIZE 16 -#define HIF_API_WAPI_KEY_DATA_SIZE 16 -#define HIF_API_MIC_KEY_DATA_SIZE 16 -#define HIF_API_IGTK_KEY_DATA_SIZE 16 -#define HIF_API_RX_SEQUENCE_COUNTER_SIZE 8 -#define HIF_API_IPN_SIZE 8 - -enum hif_key_type { - HIF_KEY_TYPE_WEP_DEFAULT = 0x0, - HIF_KEY_TYPE_WEP_PAIRWISE = 0x1, - HIF_KEY_TYPE_TKIP_GROUP = 0x2, - HIF_KEY_TYPE_TKIP_PAIRWISE = 0x3, - HIF_KEY_TYPE_AES_GROUP = 0x4, - HIF_KEY_TYPE_AES_PAIRWISE = 0x5, - HIF_KEY_TYPE_WAPI_GROUP = 0x6, - HIF_KEY_TYPE_WAPI_PAIRWISE = 0x7, - HIF_KEY_TYPE_IGTK_GROUP = 0x8, - HIF_KEY_TYPE_NONE = 0x9 -}; - -struct hif_wep_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved; - u8 key_length; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; -} __packed; - -struct hif_wep_group_key { - u8 key_id; - u8 key_length; - u8 reserved[2]; - u8 key_data[HIF_API_WEP_KEY_DATA_SIZE]; -} __packed; - -struct hif_tkip_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 tx_mic_key[HIF_API_TX_MIC_KEY_SIZE]; -} __packed; - -struct hif_tkip_group_key { - u8 tkip_key_data[HIF_API_TKIP_KEY_DATA_SIZE]; - u8 rx_mic_key[HIF_API_RX_MIC_KEY_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; -} __packed; - -struct hif_aes_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 reserved[2]; - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; -} __packed; - -struct hif_aes_group_key { - u8 aes_key_data[HIF_API_AES_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 rx_sequence_counter[HIF_API_RX_SEQUENCE_COUNTER_SIZE]; -} __packed; - -struct hif_wapi_pairwise_key { - u8 peer_address[ETH_ALEN]; - u8 key_id; - u8 reserved; - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; -} __packed; - -struct hif_wapi_group_key { - u8 wapi_key_data[HIF_API_WAPI_KEY_DATA_SIZE]; - u8 mic_key_data[HIF_API_MIC_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; -} __packed; - -struct hif_igtk_group_key { - u8 igtk_key_data[HIF_API_IGTK_KEY_DATA_SIZE]; - u8 key_id; - u8 reserved[3]; - u8 ipn[HIF_API_IPN_SIZE]; -} __packed; - -struct hif_req_add_key { - u8 type; - u8 entry_index; - u8 int_id:2; - u8 reserved1:6; - u8 reserved2; - union { - struct hif_wep_pairwise_key wep_pairwise_key; - struct hif_wep_group_key wep_group_key; - struct hif_tkip_pairwise_key tkip_pairwise_key; - struct hif_tkip_group_key tkip_group_key; - struct hif_aes_pairwise_key aes_pairwise_key; - struct hif_aes_group_key aes_group_key; - struct hif_wapi_pairwise_key wapi_pairwise_key; - struct hif_wapi_group_key wapi_group_key; - struct hif_igtk_group_key igtk_group_key; - } key; -} __packed; - -struct hif_cnf_add_key { - __le32 status; -} __packed; - -struct hif_req_remove_key { - u8 entry_index; - u8 reserved[3]; -} __packed; - -struct hif_cnf_remove_key { - __le32 status; -} __packed; - -enum hif_event_ind { - HIF_EVENT_IND_BSSLOST = 0x1, - HIF_EVENT_IND_BSSREGAINED = 0x2, - HIF_EVENT_IND_RCPI_RSSI = 0x3, - HIF_EVENT_IND_PS_MODE_ERROR = 0x4, - HIF_EVENT_IND_INACTIVITY = 0x5 -}; - -enum hif_ps_mode_error { - HIF_PS_ERROR_NO_ERROR = 0, - HIF_PS_ERROR_AP_NOT_RESP_TO_POLL = 1, - HIF_PS_ERROR_AP_NOT_RESP_TO_UAPSD_TRIGGER = 2, - HIF_PS_ERROR_AP_SENT_UNICAST_IN_DOZE = 3, - HIF_PS_ERROR_AP_NO_DATA_AFTER_TIM = 4 -}; - -struct hif_ind_event { - __le32 event_id; - union { - u8 rcpi_rssi; - __le32 ps_mode_error; - __le32 peer_sta_set; - } event_data; -} __packed; - -#endif diff --git a/drivers/staging/wfx/hif_api_general.h b/drivers/staging/wfx/hif_api_general.h deleted file mode 100644 index 24188945718d..000000000000 --- a/drivers/staging/wfx/hif_api_general.h +++ /dev/null @@ -1,267 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_GENERAL_H -#define WFX_HIF_API_GENERAL_H - -#ifdef __KERNEL__ -#include -#include -#else -#include -#include -#define __packed __attribute__((__packed__)) -#endif - -#define HIF_ID_IS_INDICATION 0x80 -#define HIF_COUNTER_MAX 7 - -struct hif_msg { - __le16 len; - u8 id; - u8 reserved:1; - u8 interface:2; - u8 seqnum:3; - u8 encrypted:2; - u8 body[]; -} __packed; - -enum hif_general_requests_ids { - HIF_REQ_ID_CONFIGURATION = 0x09, - HIF_REQ_ID_CONTROL_GPIO = 0x26, - HIF_REQ_ID_SET_SL_MAC_KEY = 0x27, - HIF_REQ_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_REQ_ID_SL_CONFIGURE = 0x29, - HIF_REQ_ID_PREVENT_ROLLBACK = 0x2a, - HIF_REQ_ID_PTA_SETTINGS = 0x2b, - HIF_REQ_ID_PTA_PRIORITY = 0x2c, - HIF_REQ_ID_PTA_STATE = 0x2d, - HIF_REQ_ID_SHUT_DOWN = 0x32, -}; - -enum hif_general_confirmations_ids { - HIF_CNF_ID_CONFIGURATION = 0x09, - HIF_CNF_ID_CONTROL_GPIO = 0x26, - HIF_CNF_ID_SET_SL_MAC_KEY = 0x27, - HIF_CNF_ID_SL_EXCHANGE_PUB_KEYS = 0x28, - HIF_CNF_ID_SL_CONFIGURE = 0x29, - HIF_CNF_ID_PREVENT_ROLLBACK = 0x2a, - HIF_CNF_ID_PTA_SETTINGS = 0x2b, - HIF_CNF_ID_PTA_PRIORITY = 0x2c, - HIF_CNF_ID_PTA_STATE = 0x2d, - HIF_CNF_ID_SHUT_DOWN = 0x32, -}; - -enum hif_general_indications_ids { - HIF_IND_ID_EXCEPTION = 0xe0, - HIF_IND_ID_STARTUP = 0xe1, - HIF_IND_ID_WAKEUP = 0xe2, - HIF_IND_ID_GENERIC = 0xe3, - HIF_IND_ID_ERROR = 0xe4, - HIF_IND_ID_SL_EXCHANGE_PUB_KEYS = 0xe5 -}; - -#define HIF_STATUS_SUCCESS (cpu_to_le32(0x0000)) -#define HIF_STATUS_FAIL (cpu_to_le32(0x0001)) -#define HIF_STATUS_INVALID_PARAMETER (cpu_to_le32(0x0002)) -#define HIF_STATUS_WARNING (cpu_to_le32(0x0003)) -#define HIF_STATUS_UNKNOWN_REQUEST (cpu_to_le32(0x0004)) -#define HIF_STATUS_RX_FAIL_DECRYPT (cpu_to_le32(0x0010)) -#define HIF_STATUS_RX_FAIL_MIC (cpu_to_le32(0x0011)) -#define HIF_STATUS_RX_FAIL_NO_KEY (cpu_to_le32(0x0012)) -#define HIF_STATUS_TX_FAIL_RETRIES (cpu_to_le32(0x0013)) -#define HIF_STATUS_TX_FAIL_TIMEOUT (cpu_to_le32(0x0014)) -#define HIF_STATUS_TX_FAIL_REQUEUE (cpu_to_le32(0x0015)) -#define HIF_STATUS_REFUSED (cpu_to_le32(0x0016)) -#define HIF_STATUS_BUSY (cpu_to_le32(0x0017)) -#define HIF_STATUS_SLK_SET_KEY_SUCCESS (cpu_to_le32(0x005A)) -#define HIF_STATUS_SLK_SET_KEY_ALREADY_BURNED (cpu_to_le32(0x006B)) -#define HIF_STATUS_SLK_SET_KEY_DISALLOWED_MODE (cpu_to_le32(0x007C)) -#define HIF_STATUS_SLK_SET_KEY_UNKNOWN_MODE (cpu_to_le32(0x008D)) -#define HIF_STATUS_SLK_NEGO_SUCCESS (cpu_to_le32(0x009E)) -#define HIF_STATUS_SLK_NEGO_FAILED (cpu_to_le32(0x00AF)) -#define HIF_STATUS_ROLLBACK_SUCCESS (cpu_to_le32(0x1234)) -#define HIF_STATUS_ROLLBACK_FAIL (cpu_to_le32(0x1256)) - -enum hif_api_rate_index { - API_RATE_INDEX_B_1MBPS = 0, - API_RATE_INDEX_B_2MBPS = 1, - API_RATE_INDEX_B_5P5MBPS = 2, - API_RATE_INDEX_B_11MBPS = 3, - API_RATE_INDEX_PBCC_22MBPS = 4, - API_RATE_INDEX_PBCC_33MBPS = 5, - API_RATE_INDEX_G_6MBPS = 6, - API_RATE_INDEX_G_9MBPS = 7, - API_RATE_INDEX_G_12MBPS = 8, - API_RATE_INDEX_G_18MBPS = 9, - API_RATE_INDEX_G_24MBPS = 10, - API_RATE_INDEX_G_36MBPS = 11, - API_RATE_INDEX_G_48MBPS = 12, - API_RATE_INDEX_G_54MBPS = 13, - API_RATE_INDEX_N_6P5MBPS = 14, - API_RATE_INDEX_N_13MBPS = 15, - API_RATE_INDEX_N_19P5MBPS = 16, - API_RATE_INDEX_N_26MBPS = 17, - API_RATE_INDEX_N_39MBPS = 18, - API_RATE_INDEX_N_52MBPS = 19, - API_RATE_INDEX_N_58P5MBPS = 20, - API_RATE_INDEX_N_65MBPS = 21, - API_RATE_NUM_ENTRIES = 22 -}; - -enum hif_fw_type { - HIF_FW_TYPE_ETF = 0x0, - HIF_FW_TYPE_WFM = 0x1, - HIF_FW_TYPE_WSM = 0x2 -}; - -struct hif_ind_startup { - // As the others, this struct is interpreted as little endian by the - // device. However, this struct is also used by the driver. We prefer to - // declare it in native order and doing byte swap on reception. - __le32 status; - u16 hardware_id; - u8 opn[14]; - u8 uid[8]; - u16 num_inp_ch_bufs; - u16 size_inp_ch_buf; - u8 num_links_ap; - u8 num_interfaces; - u8 mac_addr[2][ETH_ALEN]; - u8 api_version_minor; - u8 api_version_major; - u8 link_mode:2; - u8 reserved1:6; - u8 reserved2; - u8 reserved3; - u8 reserved4; - u8 firmware_build; - u8 firmware_minor; - u8 firmware_major; - u8 firmware_type; - u8 disabled_channel_list[2]; - u8 region_sel_mode:4; - u8 reserved5:4; - u8 phy1_region:3; - u8 phy0_region:3; - u8 otp_phy_ver:2; - u32 supported_rate_mask; - u8 firmware_label[128]; -} __packed; - -struct hif_ind_wakeup { -} __packed; - -struct hif_req_configuration { - __le16 length; - u8 pds_data[]; -} __packed; - -struct hif_cnf_configuration { - __le32 status; -} __packed; - -enum hif_gpio_mode { - HIF_GPIO_MODE_D0 = 0x0, - HIF_GPIO_MODE_D1 = 0x1, - HIF_GPIO_MODE_OD0 = 0x2, - HIF_GPIO_MODE_OD1 = 0x3, - HIF_GPIO_MODE_TRISTATE = 0x4, - HIF_GPIO_MODE_TOGGLE = 0x5, - HIF_GPIO_MODE_READ = 0x6 -}; - -struct hif_req_control_gpio { - u8 gpio_label; - u8 gpio_mode; -} __packed; - -struct hif_cnf_control_gpio { - __le32 status; - __le32 value; -} __packed; - -enum hif_generic_indication_type { - HIF_GENERIC_INDICATION_TYPE_RAW = 0x0, - HIF_GENERIC_INDICATION_TYPE_STRING = 0x1, - HIF_GENERIC_INDICATION_TYPE_RX_STATS = 0x2, - HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO = 0x3, -}; - -struct hif_rx_stats { - __le32 nb_rx_frame; - __le32 nb_crc_frame; - __le32 per_total; - __le32 throughput; - __le32 nb_rx_by_rate[API_RATE_NUM_ENTRIES]; - __le16 per[API_RATE_NUM_ENTRIES]; - __le16 snr[API_RATE_NUM_ENTRIES]; // signed value - __le16 rssi[API_RATE_NUM_ENTRIES]; // signed value - __le16 cfo[API_RATE_NUM_ENTRIES]; // signed value - __le32 date; - __le32 pwr_clk_freq; - u8 is_ext_pwr_clk; - s8 current_temp; -} __packed; - -struct hif_tx_power_loop_info { - __le16 tx_gain_dig; - __le16 tx_gain_pa; - __le16 target_pout; // signed value - __le16 p_estimation; // signed value - __le16 vpdet; - u8 measurement_index; - u8 reserved; -} __packed; - -struct hif_ind_generic { - __le32 type; - union { - struct hif_rx_stats rx_stats; - struct hif_tx_power_loop_info tx_power_loop_info; - } data; -} __packed; - -enum hif_error { - HIF_ERROR_FIRMWARE_ROLLBACK = 0x00, - HIF_ERROR_FIRMWARE_DEBUG_ENABLED = 0x01, - HIF_ERROR_SLK_OUTDATED_SESSION_KEY = 0x02, - HIF_ERROR_SLK_SESSION_KEY = 0x03, - HIF_ERROR_OOR_VOLTAGE = 0x04, - HIF_ERROR_PDS_PAYLOAD = 0x05, - HIF_ERROR_OOR_TEMPERATURE = 0x06, - HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE = 0x07, - HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED = 0x08, - HIF_ERROR_SLK_OVERFLOW = 0x09, - HIF_ERROR_SLK_DECRYPTION = 0x0a, - HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE = 0x0b, - HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW = 0x0c, - HIF_ERROR_HIF_RX_DATA_TOO_LARGE = 0x0e, - HIF_ERROR_HIF_TX_QUEUE_FULL = 0x0d, - HIF_ERROR_HIF_BUS = 0x0f, - HIF_ERROR_PDS_TESTFEATURE = 0x10, - HIF_ERROR_SLK_UNCONFIGURED = 0x11, -}; - -struct hif_ind_error { - __le32 type; - u8 data[]; -} __packed; - -struct hif_ind_exception { - __le32 type; - u8 data[]; -} __packed; - -enum hif_secure_link_state { - SEC_LINK_UNAVAILABLE = 0x0, - SEC_LINK_RESERVED = 0x1, - SEC_LINK_EVAL = 0x2, - SEC_LINK_ENFORCED = 0x3 -}; - -#endif diff --git a/drivers/staging/wfx/hif_api_mib.h b/drivers/staging/wfx/hif_api_mib.h deleted file mode 100644 index ace924720ce6..000000000000 --- a/drivers/staging/wfx/hif_api_mib.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ -/* - * WFx hardware interface definitions - * - * Copyright (c) 2018-2020, Silicon Laboratories Inc. - */ - -#ifndef WFX_HIF_API_MIB_H -#define WFX_HIF_API_MIB_H - -#include "hif_api_general.h" - -#define HIF_API_IPV4_ADDRESS_SIZE 4 -#define HIF_API_IPV6_ADDRESS_SIZE 16 - -enum hif_mib_ids { - HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE = 0x2000, - HIF_MIB_ID_GL_BLOCK_ACK_INFO = 0x2001, - HIF_MIB_ID_GL_SET_MULTI_MSG = 0x2002, - HIF_MIB_ID_CCA_CONFIG = 0x2003, - HIF_MIB_ID_ETHERTYPE_DATAFRAME_CONDITION = 0x2010, - HIF_MIB_ID_PORT_DATAFRAME_CONDITION = 0x2011, - HIF_MIB_ID_MAGIC_DATAFRAME_CONDITION = 0x2012, - HIF_MIB_ID_MAC_ADDR_DATAFRAME_CONDITION = 0x2013, - HIF_MIB_ID_IPV4_ADDR_DATAFRAME_CONDITION = 0x2014, - HIF_MIB_ID_IPV6_ADDR_DATAFRAME_CONDITION = 0x2015, - HIF_MIB_ID_UC_MC_BC_DATAFRAME_CONDITION = 0x2016, - HIF_MIB_ID_CONFIG_DATA_FILTER = 0x2017, - HIF_MIB_ID_SET_DATA_FILTERING = 0x2018, - HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE = 0x2019, - HIF_MIB_ID_NS_IP_ADDRESSES_TABLE = 0x201A, - HIF_MIB_ID_RX_FILTER = 0x201B, - HIF_MIB_ID_BEACON_FILTER_TABLE = 0x201C, - HIF_MIB_ID_BEACON_FILTER_ENABLE = 0x201D, - HIF_MIB_ID_GRP_SEQ_COUNTER = 0x2030, - HIF_MIB_ID_TSF_COUNTER = 0x2031, - HIF_MIB_ID_STATISTICS_TABLE = 0x2032, - HIF_MIB_ID_COUNTERS_TABLE = 0x2033, - HIF_MIB_ID_MAX_TX_POWER_LEVEL = 0x2034, - HIF_MIB_ID_EXTENDED_COUNTERS_TABLE = 0x2035, - HIF_MIB_ID_DOT11_MAC_ADDRESS = 0x2040, - HIF_MIB_ID_DOT11_MAX_TRANSMIT_MSDU_LIFETIME = 0x2041, - HIF_MIB_ID_DOT11_MAX_RECEIVE_LIFETIME = 0x2042, - HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID = 0x2043, - HIF_MIB_ID_DOT11_RTS_THRESHOLD = 0x2044, - HIF_MIB_ID_SLOT_TIME = 0x2045, - HIF_MIB_ID_CURRENT_TX_POWER_LEVEL = 0x2046, - HIF_MIB_ID_NON_ERP_PROTECTION = 0x2047, - HIF_MIB_ID_TEMPLATE_FRAME = 0x2048, - HIF_MIB_ID_BEACON_WAKEUP_PERIOD = 0x2049, - HIF_MIB_ID_RCPI_RSSI_THRESHOLD = 0x204A, - HIF_MIB_ID_BLOCK_ACK_POLICY = 0x204B, - HIF_MIB_ID_OVERRIDE_INTERNAL_TX_RATE = 0x204C, - HIF_MIB_ID_SET_ASSOCIATION_MODE = 0x204D, - HIF_MIB_ID_SET_UAPSD_INFORMATION = 0x204E, - HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY = 0x204F, - HIF_MIB_ID_PROTECTED_MGMT_POLICY = 0x2050, - HIF_MIB_ID_SET_HT_PROTECTION = 0x2051, - HIF_MIB_ID_KEEP_ALIVE_PERIOD = 0x2052, - HIF_MIB_ID_ARP_KEEP_ALIVE_PERIOD = 0x2053, - HIF_MIB_ID_INACTIVITY_TIMER = 0x2054, - HIF_MIB_ID_INTERFACE_PROTECTION = 0x2055, - HIF_MIB_ID_BEACON_STATS = 0x2056, -}; - -enum hif_op_power_mode { - HIF_OP_POWER_MODE_ACTIVE = 0x0, - HIF_OP_POWER_MODE_DOZE = 0x1, - HIF_OP_POWER_MODE_QUIESCENT = 0x2 -}; - -struct hif_mib_gl_operational_power_mode { - u8 power_mode:4; - u8 reserved1:3; - u8 wup_ind_activation:1; - u8 reserved2[3]; -} __packed; - -struct hif_mib_gl_set_multi_msg { - u8 enable_multi_tx_conf:1; - u8 reserved1:7; - u8 reserved2[3]; -} __packed; - -enum hif_arp_ns_frame_treatment { - HIF_ARP_NS_FILTERING_DISABLE = 0x0, - HIF_ARP_NS_FILTERING_ENABLE = 0x1, - HIF_ARP_NS_REPLY_ENABLE = 0x2 -}; - -struct hif_mib_arp_ip_addr_table { - u8 condition_idx; - u8 arp_enable; - u8 reserved[2]; - u8 ipv4_address[HIF_API_IPV4_ADDRESS_SIZE]; -} __packed; - -struct hif_mib_rx_filter { - u8 reserved1:1; - u8 bssid_filter:1; - u8 reserved2:1; - u8 fwd_probe_req:1; - u8 keep_alive_filter:1; - u8 reserved3:3; - u8 reserved4[3]; -} __packed; - -struct hif_ie_table_entry { - u8 ie_id; - u8 has_changed:1; - u8 no_longer:1; - u8 has_appeared:1; - u8 reserved:1; - u8 num_match_data:4; - u8 oui[3]; - u8 match_data[3]; -} __packed; - -struct hif_mib_bcn_filter_table { - __le32 num_of_info_elmts; - struct hif_ie_table_entry ie_table[]; -} __packed; - -enum hif_beacon_filter { - HIF_BEACON_FILTER_DISABLE = 0x0, - HIF_BEACON_FILTER_ENABLE = 0x1, - HIF_BEACON_FILTER_AUTO_ERP = 0x2 -}; - -struct hif_mib_bcn_filter_enable { - __le32 enable; - __le32 bcn_count; -} __packed; - -struct hif_mib_extended_count_table { - __le32 count_plcp_errors; - __le32 count_fcs_errors; - __le32 count_tx_packets; - __le32 count_rx_packets; - __le32 count_rx_packet_errors; - __le32 count_rx_decryption_failures; - __le32 count_rx_mic_failures; - __le32 count_rx_no_key_failures; - __le32 count_tx_multicast_frames; - __le32 count_tx_frames_success; - __le32 count_tx_frame_failures; - __le32 count_tx_frames_retried; - __le32 count_tx_frames_multi_retried; - __le32 count_rx_frame_duplicates; - __le32 count_rts_success; - __le32 count_rts_failures; - __le32 count_ack_failures; - __le32 count_rx_multicast_frames; - __le32 count_rx_frames_success; - __le32 count_rx_cmacicv_errors; - __le32 count_rx_cmac_replays; - __le32 count_rx_mgmt_ccmp_replays; - __le32 count_rx_bipmic_errors; - __le32 count_rx_beacon; - __le32 count_miss_beacon; - __le32 reserved[15]; -} __packed; - -struct hif_mib_count_table { - __le32 count_plcp_errors; - __le32 count_fcs_errors; - __le32 count_tx_packets; - __le32 count_rx_packets; - __le32 count_rx_packet_errors; - __le32 count_rx_decryption_failures; - __le32 count_rx_mic_failures; - __le32 count_rx_no_key_failures; - __le32 count_tx_multicast_frames; - __le32 count_tx_frames_success; - __le32 count_tx_frame_failures; - __le32 count_tx_frames_retried; - __le32 count_tx_frames_multi_retried; - __le32 count_rx_frame_duplicates; - __le32 count_rts_success; - __le32 count_rts_failures; - __le32 count_ack_failures; - __le32 count_rx_multicast_frames; - __le32 count_rx_frames_success; - __le32 count_rx_cmacicv_errors; - __le32 count_rx_cmac_replays; - __le32 count_rx_mgmt_ccmp_replays; - __le32 count_rx_bipmic_errors; -} __packed; - -struct hif_mib_mac_address { - u8 mac_addr[ETH_ALEN]; - __le16 reserved; -} __packed; - -struct hif_mib_wep_default_key_id { - u8 wep_default_key_id; - u8 reserved[3]; -} __packed; - -struct hif_mib_dot11_rts_threshold { - __le32 threshold; -} __packed; - -struct hif_mib_slot_time { - __le32 slot_time; -} __packed; - -struct hif_mib_current_tx_power_level { - __le32 power_level; // signed value -} __packed; - -struct hif_mib_non_erp_protection { - u8 use_cts_to_self:1; - u8 reserved1:7; - u8 reserved2[3]; -} __packed; - -enum hif_tmplt { - HIF_TMPLT_PRBREQ = 0x0, - HIF_TMPLT_BCN = 0x1, - HIF_TMPLT_NULL = 0x2, - HIF_TMPLT_QOSNUL = 0x3, - HIF_TMPLT_PSPOLL = 0x4, - HIF_TMPLT_PRBRES = 0x5, - HIF_TMPLT_ARP = 0x6, - HIF_TMPLT_NA = 0x7 -}; - -#define HIF_API_MAX_TEMPLATE_FRAME_SIZE 700 - -struct hif_mib_template_frame { - u8 frame_type; - u8 init_rate:7; - u8 mode:1; - __le16 frame_length; - u8 frame[]; -} __packed; - -struct hif_mib_beacon_wake_up_period { - u8 wakeup_period_min; - u8 receive_dtim:1; - u8 reserved1:7; - u8 wakeup_period_max; - u8 reserved2; -} __packed; - -struct hif_mib_rcpi_rssi_threshold { - u8 detection:1; - u8 rcpi_rssi:1; - u8 upperthresh:1; - u8 lowerthresh:1; - u8 reserved:4; - u8 lower_threshold; - u8 upper_threshold; - u8 rolling_average_count; -} __packed; - -#define DEFAULT_BA_MAX_RX_BUFFER_SIZE 16 - -struct hif_mib_block_ack_policy { - u8 block_ack_tx_tid_policy; - u8 reserved1; - u8 block_ack_rx_tid_policy; - u8 block_ack_rx_max_buffer_size; -} __packed; - -enum hif_mpdu_start_spacing { - HIF_MPDU_START_SPACING_NO_RESTRIC = 0x0, - HIF_MPDU_START_SPACING_QUARTER = 0x1, - HIF_MPDU_START_SPACING_HALF = 0x2, - HIF_MPDU_START_SPACING_ONE = 0x3, - HIF_MPDU_START_SPACING_TWO = 0x4, - HIF_MPDU_START_SPACING_FOUR = 0x5, - HIF_MPDU_START_SPACING_EIGHT = 0x6, - HIF_MPDU_START_SPACING_SIXTEEN = 0x7 -}; - -struct hif_mib_set_association_mode { - u8 preambtype_use:1; - u8 mode:1; - u8 rateset:1; - u8 spacing:1; - u8 reserved1:4; - u8 short_preamble:1; - u8 reserved2:7; - u8 greenfield:1; - u8 reserved3:7; - u8 mpdu_start_spacing; - __le32 basic_rate_set; -} __packed; - -struct hif_mib_set_uapsd_information { - u8 trig_bckgrnd:1; - u8 trig_be:1; - u8 trig_video:1; - u8 trig_voice:1; - u8 reserved1:4; - u8 deliv_bckgrnd:1; - u8 deliv_be:1; - u8 deliv_video:1; - u8 deliv_voice:1; - u8 reserved2:4; - __le16 min_auto_trigger_interval; - __le16 max_auto_trigger_interval; - __le16 auto_trigger_step; -} __packed; - -struct hif_tx_rate_retry_policy { - u8 policy_index; - u8 short_retry_count; - u8 long_retry_count; - u8 first_rate_sel:2; - u8 terminate:1; - u8 count_init:1; - u8 reserved1:4; - u8 rate_recovery_count; - u8 reserved2[3]; - u8 rates[12]; -} __packed; - -#define HIF_TX_RETRY_POLICY_MAX 15 -#define HIF_TX_RETRY_POLICY_INVALID HIF_TX_RETRY_POLICY_MAX - -struct hif_mib_set_tx_rate_retry_policy { - u8 num_tx_rate_policies; - u8 reserved[3]; - struct hif_tx_rate_retry_policy tx_rate_retry_policy[]; -} __packed; - -struct hif_mib_protected_mgmt_policy { - u8 pmf_enable:1; - u8 unpmf_allowed:1; - u8 host_enc_auth_frames:1; - u8 reserved1:5; - u8 reserved2[3]; -} __packed; - -struct hif_mib_keep_alive_period { - __le16 keep_alive_period; - u8 reserved[2]; -} __packed; - -#endif diff --git a/drivers/staging/wfx/hif_rx.c b/drivers/staging/wfx/hif_rx.c deleted file mode 100644 index 56a5f891447b..000000000000 --- a/drivers/staging/wfx/hif_rx.c +++ /dev/null @@ -1,415 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac - * (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "hif_rx.h" -#include "wfx.h" -#include "scan.h" -#include "bh.h" -#include "sta.h" -#include "data_rx.h" -#include "hif_api_cmd.h" - -static int hif_generic_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - // All confirm messages start with status - int status = le32_to_cpup((__le32 *)buf); - int cmd = hif->id; - int len = le16_to_cpu(hif->len) - 4; // drop header - - WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); - - if (!wdev->hif_cmd.buf_send) { - dev_warn(wdev->dev, "unexpected confirmation: 0x%.2x\n", cmd); - return -EINVAL; - } - - if (cmd != wdev->hif_cmd.buf_send->id) { - dev_warn(wdev->dev, - "chip response mismatch request: 0x%.2x vs 0x%.2x\n", - cmd, wdev->hif_cmd.buf_send->id); - return -EINVAL; - } - - if (wdev->hif_cmd.buf_recv) { - if (wdev->hif_cmd.len_recv >= len && len > 0) - memcpy(wdev->hif_cmd.buf_recv, buf, len); - else - status = -EIO; - } - wdev->hif_cmd.ret = status; - - complete(&wdev->hif_cmd.done); - return status; -} - -static int hif_tx_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_cnf_tx *body = buf; - - wfx_tx_confirm_cb(wdev, body); - return 0; -} - -static int hif_multi_tx_confirm(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_cnf_multi_transmit *body = buf; - int i; - - WARN(body->num_tx_confs <= 0, "corrupted message"); - for (i = 0; i < body->num_tx_confs; i++) - wfx_tx_confirm_cb(wdev, &body->tx_conf_payload[i]); - return 0; -} - -static int hif_startup_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_startup *body = buf; - - if (body->status || body->firmware_type > 4) { - dev_err(wdev->dev, "received invalid startup indication"); - return -EINVAL; - } - memcpy(&wdev->hw_caps, body, sizeof(struct hif_ind_startup)); - le16_to_cpus((__le16 *)&wdev->hw_caps.hardware_id); - le16_to_cpus((__le16 *)&wdev->hw_caps.num_inp_ch_bufs); - le16_to_cpus((__le16 *)&wdev->hw_caps.size_inp_ch_buf); - le32_to_cpus((__le32 *)&wdev->hw_caps.supported_rate_mask); - - complete(&wdev->firmware_ready); - return 0; -} - -static int hif_wakeup_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - if (!wdev->pdata.gpio_wakeup || - gpiod_get_value(wdev->pdata.gpio_wakeup) == 0) { - dev_warn(wdev->dev, "unexpected wake-up indication\n"); - return -EIO; - } - return 0; -} - -static int hif_receive_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf, struct sk_buff *skb) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - const struct hif_ind_rx *body = buf; - - if (!wvif) { - dev_warn(wdev->dev, "%s: ignore rx data for non-existent vif %d\n", - __func__, hif->interface); - return -EIO; - } - skb_pull(skb, sizeof(struct hif_msg) + sizeof(struct hif_ind_rx)); - wfx_rx_cb(wvif, body, skb); - - return 0; -} - -static int hif_event_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - const struct hif_ind_event *body = buf; - int type = le32_to_cpu(body->event_id); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - - switch (type) { - case HIF_EVENT_IND_RCPI_RSSI: - wfx_event_report_rssi(wvif, body->event_data.rcpi_rssi); - break; - case HIF_EVENT_IND_BSSLOST: - schedule_delayed_work(&wvif->beacon_loss_work, 0); - break; - case HIF_EVENT_IND_BSSREGAINED: - cancel_delayed_work(&wvif->beacon_loss_work); - dev_dbg(wdev->dev, "ignore BSSREGAINED indication\n"); - break; - case HIF_EVENT_IND_PS_MODE_ERROR: - dev_warn(wdev->dev, "error while processing power save request: %d\n", - le32_to_cpu(body->event_data.ps_mode_error)); - break; - default: - dev_warn(wdev->dev, "unhandled event indication: %.2x\n", - type); - break; - } - return 0; -} - -static int hif_pm_mode_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - complete(&wvif->set_pm_mode_complete); - - return 0; -} - -static int hif_scan_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - - wfx_scan_complete(wvif); - - return 0; -} - -static int hif_join_complete_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - struct wfx_vif *wvif = wdev_to_wvif(wdev, hif->interface); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - dev_warn(wdev->dev, "unattended JoinCompleteInd\n"); - - return 0; -} - -static int hif_suspend_resume_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, - const void *buf) -{ - const struct hif_ind_suspend_resume_tx *body = buf; - struct wfx_vif *wvif; - - if (body->bc_mc_only) { - wvif = wdev_to_wvif(wdev, hif->interface); - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - if (body->resume) - wfx_suspend_resume_mc(wvif, STA_NOTIFY_AWAKE); - else - wfx_suspend_resume_mc(wvif, STA_NOTIFY_SLEEP); - } else { - WARN(body->peer_sta_set, "misunderstood indication"); - WARN(hif->interface != 2, "misunderstood indication"); - if (body->resume) - wfx_suspend_hot_dev(wdev, STA_NOTIFY_AWAKE); - else - wfx_suspend_hot_dev(wdev, STA_NOTIFY_SLEEP); - } - - return 0; -} - -static int hif_generic_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_generic *body = buf; - int type = le32_to_cpu(body->type); - - switch (type) { - case HIF_GENERIC_INDICATION_TYPE_RAW: - return 0; - case HIF_GENERIC_INDICATION_TYPE_STRING: - dev_info(wdev->dev, "firmware says: %s\n", (char *)&body->data); - return 0; - case HIF_GENERIC_INDICATION_TYPE_RX_STATS: - mutex_lock(&wdev->rx_stats_lock); - // Older firmware send a generic indication beside RxStats - if (!wfx_api_older_than(wdev, 1, 4)) - dev_info(wdev->dev, "Rx test ongoing. Temperature: %d degrees C\n", - body->data.rx_stats.current_temp); - memcpy(&wdev->rx_stats, &body->data.rx_stats, - sizeof(wdev->rx_stats)); - mutex_unlock(&wdev->rx_stats_lock); - return 0; - case HIF_GENERIC_INDICATION_TYPE_TX_POWER_LOOP_INFO: - mutex_lock(&wdev->tx_power_loop_info_lock); - memcpy(&wdev->tx_power_loop_info, - &body->data.tx_power_loop_info, - sizeof(wdev->tx_power_loop_info)); - mutex_unlock(&wdev->tx_power_loop_info_lock); - return 0; - default: - dev_err(wdev->dev, "generic_indication: unknown indication type: %#.8x\n", - type); - return -EIO; - } -} - -static const struct { - int val; - const char *str; - bool has_param; -} hif_errors[] = { - { HIF_ERROR_FIRMWARE_ROLLBACK, - "rollback status" }, - { HIF_ERROR_FIRMWARE_DEBUG_ENABLED, - "debug feature enabled" }, - { HIF_ERROR_PDS_PAYLOAD, - "PDS version is not supported" }, - { HIF_ERROR_PDS_TESTFEATURE, - "PDS ask for an unknown test mode" }, - { HIF_ERROR_OOR_VOLTAGE, - "out-of-range power supply voltage", true }, - { HIF_ERROR_OOR_TEMPERATURE, - "out-of-range temperature", true }, - { HIF_ERROR_SLK_REQ_DURING_KEY_EXCHANGE, - "secure link does not expect request during key exchange" }, - { HIF_ERROR_SLK_SESSION_KEY, - "secure link session key is invalid" }, - { HIF_ERROR_SLK_OVERFLOW, - "secure link overflow" }, - { HIF_ERROR_SLK_WRONG_ENCRYPTION_STATE, - "secure link messages list does not match message encryption" }, - { HIF_ERROR_SLK_UNCONFIGURED, - "secure link not yet configured" }, - { HIF_ERROR_HIF_BUS_FREQUENCY_TOO_LOW, - "bus clock is too slow (<1kHz)" }, - { HIF_ERROR_HIF_RX_DATA_TOO_LARGE, - "HIF message too large" }, - // Following errors only exists in old firmware versions: - { HIF_ERROR_HIF_TX_QUEUE_FULL, - "HIF messages queue is full" }, - { HIF_ERROR_HIF_BUS, - "HIF bus" }, - { HIF_ERROR_SLK_MULTI_TX_UNSUPPORTED, - "secure link does not support multi-tx confirmations" }, - { HIF_ERROR_SLK_OUTDATED_SESSION_KEY, - "secure link session key is outdated" }, - { HIF_ERROR_SLK_DECRYPTION, - "secure link params (nonce or tag) mismatch" }, -}; - -static int hif_error_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_error *body = buf; - int type = le32_to_cpu(body->type); - int param = (s8)body->data[0]; - int i; - - for (i = 0; i < ARRAY_SIZE(hif_errors); i++) - if (type == hif_errors[i].val) - break; - if (i < ARRAY_SIZE(hif_errors)) - if (hif_errors[i].has_param) - dev_err(wdev->dev, "asynchronous error: %s: %d\n", - hif_errors[i].str, param); - else - dev_err(wdev->dev, "asynchronous error: %s\n", - hif_errors[i].str); - else - dev_err(wdev->dev, "asynchronous error: unknown: %08x\n", type); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, - 16, 1, hif, le16_to_cpu(hif->len), false); - wdev->chip_frozen = true; - - return 0; -}; - -static int hif_exception_indication(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf) -{ - const struct hif_ind_exception *body = buf; - int type = le32_to_cpu(body->type); - - if (type == 4) - dev_err(wdev->dev, "firmware assert %d\n", - le32_to_cpup((__le32 *)body->data)); - else - dev_err(wdev->dev, "firmware exception\n"); - print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, - 16, 1, hif, le16_to_cpu(hif->len), false); - wdev->chip_frozen = true; - - return -1; -} - -static const struct { - int msg_id; - int (*handler)(struct wfx_dev *wdev, - const struct hif_msg *hif, const void *buf); -} hif_handlers[] = { - /* Confirmations */ - { HIF_CNF_ID_TX, hif_tx_confirm }, - { HIF_CNF_ID_MULTI_TRANSMIT, hif_multi_tx_confirm }, - /* Indications */ - { HIF_IND_ID_STARTUP, hif_startup_indication }, - { HIF_IND_ID_WAKEUP, hif_wakeup_indication }, - { HIF_IND_ID_JOIN_COMPLETE, hif_join_complete_indication }, - { HIF_IND_ID_SET_PM_MODE_CMPL, hif_pm_mode_complete_indication }, - { HIF_IND_ID_SCAN_CMPL, hif_scan_complete_indication }, - { HIF_IND_ID_SUSPEND_RESUME_TX, hif_suspend_resume_indication }, - { HIF_IND_ID_EVENT, hif_event_indication }, - { HIF_IND_ID_GENERIC, hif_generic_indication }, - { HIF_IND_ID_ERROR, hif_error_indication }, - { HIF_IND_ID_EXCEPTION, hif_exception_indication }, - // FIXME: allocate skb_p from hif_receive_indication and make it generic - //{ HIF_IND_ID_RX, hif_receive_indication }, -}; - -void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb) -{ - int i; - const struct hif_msg *hif = (const struct hif_msg *)skb->data; - int hif_id = hif->id; - - if (hif_id == HIF_IND_ID_RX) { - // hif_receive_indication take care of skb lifetime - hif_receive_indication(wdev, hif, hif->body, skb); - return; - } - // Note: mutex_is_lock cause an implicit memory barrier that protect - // buf_send - if (mutex_is_locked(&wdev->hif_cmd.lock) - && wdev->hif_cmd.buf_send - && wdev->hif_cmd.buf_send->id == hif_id) { - hif_generic_confirm(wdev, hif, hif->body); - goto free; - } - for (i = 0; i < ARRAY_SIZE(hif_handlers); i++) { - if (hif_handlers[i].msg_id == hif_id) { - if (hif_handlers[i].handler) - hif_handlers[i].handler(wdev, hif, hif->body); - goto free; - } - } - if (hif_id & 0x80) - dev_err(wdev->dev, "unsupported HIF indication: ID %02x\n", - hif_id); - else - dev_err(wdev->dev, "unexpected HIF confirmation: ID %02x\n", - hif_id); -free: - dev_kfree_skb(skb); -} diff --git a/drivers/staging/wfx/hif_rx.h b/drivers/staging/wfx/hif_rx.h deleted file mode 100644 index f07c10c8c6bd..000000000000 --- a/drivers/staging/wfx/hif_rx.h +++ /dev/null @@ -1,18 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of chip-to-host event (aka indications) of WFxxx Split Mac - * (WSM) API. - * - * Copyright (c) 2017-2019, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (C) 2010, ST-Ericsson SA - */ -#ifndef WFX_HIF_RX_H -#define WFX_HIF_RX_H - -struct wfx_dev; -struct sk_buff; - -void wfx_handle_rx(struct wfx_dev *wdev, struct sk_buff *skb); - -#endif diff --git a/drivers/staging/wfx/hif_tx.c b/drivers/staging/wfx/hif_tx.c deleted file mode 100644 index 63b437261eb7..000000000000 --- a/drivers/staging/wfx/hif_tx.c +++ /dev/null @@ -1,523 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx - * Split Mac (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include - -#include "hif_tx.h" -#include "wfx.h" -#include "bh.h" -#include "hwio.h" -#include "debug.h" -#include "sta.h" - -void wfx_init_hif_cmd(struct wfx_hif_cmd *hif_cmd) -{ - init_completion(&hif_cmd->ready); - init_completion(&hif_cmd->done); - mutex_init(&hif_cmd->lock); -} - -static void wfx_fill_header(struct hif_msg *hif, int if_id, - unsigned int cmd, size_t size) -{ - if (if_id == -1) - if_id = 2; - - WARN(cmd > 0x3f, "invalid WSM command %#.2x", cmd); - WARN(size > 0xFFF, "requested buffer is too large: %zu bytes", size); - WARN(if_id > 0x3, "invalid interface ID %d", if_id); - - hif->len = cpu_to_le16(size + 4); - hif->id = cmd; - hif->interface = if_id; -} - -static void *wfx_alloc_hif(size_t body_len, struct hif_msg **hif) -{ - *hif = kzalloc(sizeof(struct hif_msg) + body_len, GFP_KERNEL); - if (*hif) - return (*hif)->body; - else - return NULL; -} - -int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, - void *reply, size_t reply_len, bool no_reply) -{ - const char *mib_name = ""; - const char *mib_sep = ""; - int cmd = request->id; - int vif = request->interface; - int ret; - - // Do not wait for any reply if chip is frozen - if (wdev->chip_frozen) - return -ETIMEDOUT; - - mutex_lock(&wdev->hif_cmd.lock); - WARN(wdev->hif_cmd.buf_send, "data locking error"); - - // Note: call to complete() below has an implicit memory barrier that - // hopefully protect buf_send - wdev->hif_cmd.buf_send = request; - wdev->hif_cmd.buf_recv = reply; - wdev->hif_cmd.len_recv = reply_len; - complete(&wdev->hif_cmd.ready); - - wfx_bh_request_tx(wdev); - - if (no_reply) { - // Chip won't reply. Give enough time to the wq to send the - // buffer. - msleep(100); - wdev->hif_cmd.buf_send = NULL; - mutex_unlock(&wdev->hif_cmd.lock); - return 0; - } - - if (wdev->poll_irq) - wfx_bh_poll_irq(wdev); - - ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 1 * HZ); - if (!ret) { - dev_err(wdev->dev, "chip is abnormally long to answer\n"); - reinit_completion(&wdev->hif_cmd.ready); - ret = wait_for_completion_timeout(&wdev->hif_cmd.done, 3 * HZ); - } - if (!ret) { - dev_err(wdev->dev, "chip did not answer\n"); - wfx_pending_dump_old_frames(wdev, 3000); - wdev->chip_frozen = true; - reinit_completion(&wdev->hif_cmd.done); - ret = -ETIMEDOUT; - } else { - ret = wdev->hif_cmd.ret; - } - - wdev->hif_cmd.buf_send = NULL; - mutex_unlock(&wdev->hif_cmd.lock); - - if (ret && - (cmd == HIF_REQ_ID_READ_MIB || cmd == HIF_REQ_ID_WRITE_MIB)) { - mib_name = get_mib_name(((u16 *)request)[2]); - mib_sep = "/"; - } - if (ret < 0) - dev_err(wdev->dev, - "WSM request %s%s%s (%#.2x) on vif %d returned error %d\n", - get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); - if (ret > 0) - dev_warn(wdev->dev, - "WSM request %s%s%s (%#.2x) on vif %d returned status %d\n", - get_hif_name(cmd), mib_sep, mib_name, cmd, vif, ret); - - return ret; -} - -// This function is special. After HIF_REQ_ID_SHUT_DOWN, chip won't reply to any -// request anymore. Obviously, only call this function during device unregister. -int hif_shutdown(struct wfx_dev *wdev) -{ - int ret; - struct hif_msg *hif; - - wfx_alloc_hif(0, &hif); - if (!hif) - return -ENOMEM; - wfx_fill_header(hif, -1, HIF_REQ_ID_SHUT_DOWN, 0); - ret = wfx_cmd_send(wdev, hif, NULL, 0, true); - if (wdev->pdata.gpio_wakeup) - gpiod_set_value(wdev->pdata.gpio_wakeup, 0); - else - control_reg_write(wdev, 0); - kfree(hif); - return ret; -} - -int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len) -{ - int ret; - size_t buf_len = sizeof(struct hif_req_configuration) + len; - struct hif_msg *hif; - struct hif_req_configuration *body = wfx_alloc_hif(buf_len, &hif); - - if (!hif) - return -ENOMEM; - body->length = cpu_to_le16(len); - memcpy(body->pds_data, conf, len); - wfx_fill_header(hif, -1, HIF_REQ_ID_CONFIGURATION, buf_len); - ret = wfx_cmd_send(wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_reset(struct wfx_vif *wvif, bool reset_stat) -{ - int ret; - struct hif_msg *hif; - struct hif_req_reset *body = wfx_alloc_hif(sizeof(*body), &hif); - - if (!hif) - return -ENOMEM; - body->reset_stat = reset_stat; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_RESET, sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, - void *val, size_t val_len) -{ - int ret; - struct hif_msg *hif; - int buf_len = sizeof(struct hif_cnf_read_mib) + val_len; - struct hif_req_read_mib *body = wfx_alloc_hif(sizeof(*body), &hif); - struct hif_cnf_read_mib *reply = kmalloc(buf_len, GFP_KERNEL); - - if (!body || !reply) { - ret = -ENOMEM; - goto out; - } - body->mib_id = cpu_to_le16(mib_id); - wfx_fill_header(hif, vif_id, HIF_REQ_ID_READ_MIB, sizeof(*body)); - ret = wfx_cmd_send(wdev, hif, reply, buf_len, false); - - if (!ret && mib_id != le16_to_cpu(reply->mib_id)) { - dev_warn(wdev->dev, "%s: confirmation mismatch request\n", - __func__); - ret = -EIO; - } - if (ret == -ENOMEM) - dev_err(wdev->dev, "buffer is too small to receive %s (%zu < %d)\n", - get_mib_name(mib_id), val_len, - le16_to_cpu(reply->length)); - if (!ret) - memcpy(val, &reply->mib_data, le16_to_cpu(reply->length)); - else - memset(val, 0xFF, val_len); -out: - kfree(hif); - kfree(reply); - return ret; -} - -int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, - void *val, size_t val_len) -{ - int ret; - struct hif_msg *hif; - int buf_len = sizeof(struct hif_req_write_mib) + val_len; - struct hif_req_write_mib *body = wfx_alloc_hif(buf_len, &hif); - - if (!hif) - return -ENOMEM; - body->mib_id = cpu_to_le16(mib_id); - body->length = cpu_to_le16(val_len); - memcpy(&body->mib_data, val, val_len); - wfx_fill_header(hif, vif_id, HIF_REQ_ID_WRITE_MIB, buf_len); - ret = wfx_cmd_send(wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req, - int chan_start_idx, int chan_num, int *timeout) -{ - int ret, i; - struct hif_msg *hif; - size_t buf_len = - sizeof(struct hif_req_start_scan_alt) + chan_num * sizeof(u8); - struct hif_req_start_scan_alt *body = wfx_alloc_hif(buf_len, &hif); - int tmo_chan_fg, tmo_chan_bg, tmo; - - WARN(chan_num > HIF_API_MAX_NB_CHANNELS, "invalid params"); - WARN(req->n_ssids > HIF_API_MAX_NB_SSIDS, "invalid params"); - - if (!hif) - return -ENOMEM; - for (i = 0; i < req->n_ssids; i++) { - memcpy(body->ssid_def[i].ssid, req->ssids[i].ssid, - IEEE80211_MAX_SSID_LEN); - body->ssid_def[i].ssid_length = - cpu_to_le32(req->ssids[i].ssid_len); - } - body->num_of_ssids = HIF_API_MAX_NB_SSIDS; - body->maintain_current_bss = 1; - body->disallow_ps = 1; - body->tx_power_level = - cpu_to_le32(req->channels[chan_start_idx]->max_power); - body->num_of_channels = chan_num; - for (i = 0; i < chan_num; i++) - body->channel_list[i] = - req->channels[i + chan_start_idx]->hw_value; - if (req->no_cck) - body->max_transmit_rate = API_RATE_INDEX_G_6MBPS; - else - body->max_transmit_rate = API_RATE_INDEX_B_1MBPS; - if (req->channels[chan_start_idx]->flags & IEEE80211_CHAN_NO_IR) { - body->min_channel_time = cpu_to_le32(50); - body->max_channel_time = cpu_to_le32(150); - } else { - body->min_channel_time = cpu_to_le32(10); - body->max_channel_time = cpu_to_le32(50); - body->num_of_probe_requests = 2; - body->probe_delay = 100; - } - tmo_chan_bg = le32_to_cpu(body->max_channel_time) * USEC_PER_TU; - tmo_chan_fg = 512 * USEC_PER_TU + body->probe_delay; - tmo_chan_fg *= body->num_of_probe_requests; - tmo = chan_num * max(tmo_chan_bg, tmo_chan_fg) + 512 * USEC_PER_TU; - if (timeout) - *timeout = usecs_to_jiffies(tmo); - - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START_SCAN, buf_len); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_stop_scan(struct wfx_vif *wvif) -{ - int ret; - struct hif_msg *hif; - // body associated to HIF_REQ_ID_STOP_SCAN is empty - wfx_alloc_hif(0, &hif); - - if (!hif) - return -ENOMEM; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_STOP_SCAN, 0); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, - struct ieee80211_channel *channel, const u8 *ssid, int ssidlen) -{ - int ret; - struct hif_msg *hif; - struct hif_req_join *body = wfx_alloc_hif(sizeof(*body), &hif); - - WARN_ON(!conf->beacon_int); - WARN_ON(!conf->basic_rates); - WARN_ON(sizeof(body->ssid) < ssidlen); - WARN(!conf->ibss_joined && !ssidlen, "joining an unknown BSS"); - if (WARN_ON(!channel)) - return -EINVAL; - if (!hif) - return -ENOMEM; - body->infrastructure_bss_mode = !conf->ibss_joined; - body->short_preamble = conf->use_short_preamble; - if (channel->flags & IEEE80211_CHAN_NO_IR) - body->probe_for_join = 0; - else - body->probe_for_join = 1; - body->channel_number = channel->hw_value; - body->beacon_interval = cpu_to_le32(conf->beacon_int); - body->basic_rate_set = - cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); - memcpy(body->bssid, conf->bssid, sizeof(body->bssid)); - if (ssid) { - body->ssid_length = cpu_to_le32(ssidlen); - memcpy(body->ssid, ssid, ssidlen); - } - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_JOIN, sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count) -{ - int ret; - struct hif_msg *hif; - struct hif_req_set_bss_params *body = - wfx_alloc_hif(sizeof(*body), &hif); - - if (!hif) - return -ENOMEM; - body->aid = cpu_to_le16(aid); - body->beacon_lost_count = beacon_lost_count; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_BSS_PARAMS, - sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg) -{ - int ret; - struct hif_msg *hif; - // FIXME: only send necessary bits - struct hif_req_add_key *body = wfx_alloc_hif(sizeof(*body), &hif); - - if (!hif) - return -ENOMEM; - // FIXME: swap bytes as necessary in body - memcpy(body, arg, sizeof(*body)); - if (wfx_api_older_than(wdev, 1, 5)) - // Legacy firmwares expect that add_key to be sent on right - // interface. - wfx_fill_header(hif, arg->int_id, HIF_REQ_ID_ADD_KEY, - sizeof(*body)); - else - wfx_fill_header(hif, -1, HIF_REQ_ID_ADD_KEY, sizeof(*body)); - ret = wfx_cmd_send(wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_remove_key(struct wfx_dev *wdev, int idx) -{ - int ret; - struct hif_msg *hif; - struct hif_req_remove_key *body = wfx_alloc_hif(sizeof(*body), &hif); - - if (!hif) - return -ENOMEM; - body->entry_index = idx; - wfx_fill_header(hif, -1, HIF_REQ_ID_REMOVE_KEY, sizeof(*body)); - ret = wfx_cmd_send(wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, - const struct ieee80211_tx_queue_params *arg) -{ - int ret; - struct hif_msg *hif; - struct hif_req_edca_queue_params *body = wfx_alloc_hif(sizeof(*body), - &hif); - - if (!body) - return -ENOMEM; - - WARN_ON(arg->aifs > 255); - if (!hif) - return -ENOMEM; - body->aifsn = arg->aifs; - body->cw_min = cpu_to_le16(arg->cw_min); - body->cw_max = cpu_to_le16(arg->cw_max); - body->tx_op_limit = cpu_to_le16(arg->txop * USEC_PER_TXOP); - body->queue_id = 3 - queue; - // API 2.0 has changed queue IDs values - if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BE) - body->queue_id = HIF_QUEUE_ID_BACKGROUND; - if (wfx_api_older_than(wvif->wdev, 2, 0) && queue == IEEE80211_AC_BK) - body->queue_id = HIF_QUEUE_ID_BESTEFFORT; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_EDCA_QUEUE_PARAMS, - sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout) -{ - int ret; - struct hif_msg *hif; - struct hif_req_set_pm_mode *body = wfx_alloc_hif(sizeof(*body), &hif); - - if (!body) - return -ENOMEM; - - if (!hif) - return -ENOMEM; - if (ps) { - body->enter_psm = 1; - // Firmware does not support more than 128ms - body->fast_psm_idle_period = min(dynamic_ps_timeout * 2, 255); - if (body->fast_psm_idle_period) - body->fast_psm = 1; - } - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_SET_PM_MODE, sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, - const struct ieee80211_channel *channel) -{ - int ret; - struct hif_msg *hif; - struct hif_req_start *body = wfx_alloc_hif(sizeof(*body), &hif); - - WARN_ON(!conf->beacon_int); - if (!hif) - return -ENOMEM; - body->dtim_period = conf->dtim_period; - body->short_preamble = conf->use_short_preamble; - body->channel_number = channel->hw_value; - body->beacon_interval = cpu_to_le32(conf->beacon_int); - body->basic_rate_set = - cpu_to_le32(wfx_rate_mask_to_hw(wvif->wdev, conf->basic_rates)); - body->ssid_length = conf->ssid_len; - memcpy(body->ssid, conf->ssid, conf->ssid_len); - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_START, sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_beacon_transmit(struct wfx_vif *wvif, bool enable) -{ - int ret; - struct hif_msg *hif; - struct hif_req_beacon_transmit *body = wfx_alloc_hif(sizeof(*body), - &hif); - - if (!hif) - return -ENOMEM; - body->enable_beaconing = enable ? 1 : 0; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_BEACON_TRANSMIT, - sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_map_link(struct wfx_vif *wvif, bool unmap, u8 *mac_addr, int sta_id, bool mfp) -{ - int ret; - struct hif_msg *hif; - struct hif_req_map_link *body = wfx_alloc_hif(sizeof(*body), &hif); - - if (!hif) - return -ENOMEM; - if (mac_addr) - ether_addr_copy(body->mac_addr, mac_addr); - body->mfpc = mfp ? 1 : 0; - body->unmap = unmap ? 1 : 0; - body->peer_sta_id = sta_id; - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_MAP_LINK, sizeof(*body)); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} - -int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len) -{ - int ret; - struct hif_msg *hif; - int buf_len = sizeof(struct hif_req_update_ie) + ies_len; - struct hif_req_update_ie *body = wfx_alloc_hif(buf_len, &hif); - - if (!hif) - return -ENOMEM; - body->beacon = 1; - body->num_ies = cpu_to_le16(1); - memcpy(body->ie, ies, ies_len); - wfx_fill_header(hif, wvif->id, HIF_REQ_ID_UPDATE_IE, buf_len); - ret = wfx_cmd_send(wvif->wdev, hif, NULL, 0, false); - kfree(hif); - return ret; -} diff --git a/drivers/staging/wfx/hif_tx.h b/drivers/staging/wfx/hif_tx.h deleted file mode 100644 index 3521c545ae6b..000000000000 --- a/drivers/staging/wfx/hif_tx.h +++ /dev/null @@ -1,60 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of host-to-chip commands (aka request/confirmation) of WFxxx - * Split Mac (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (C) 2010, ST-Ericsson SA - */ -#ifndef WFX_HIF_TX_H -#define WFX_HIF_TX_H - -struct ieee80211_channel; -struct ieee80211_bss_conf; -struct ieee80211_tx_queue_params; -struct cfg80211_scan_request; -struct hif_req_add_key; -struct wfx_dev; -struct wfx_vif; - -struct wfx_hif_cmd { - struct mutex lock; - struct completion ready; - struct completion done; - struct hif_msg *buf_send; - void *buf_recv; - size_t len_recv; - int ret; -}; - -void wfx_init_hif_cmd(struct wfx_hif_cmd *wfx_hif_cmd); -int wfx_cmd_send(struct wfx_dev *wdev, struct hif_msg *request, - void *reply, size_t reply_len, bool async); - -int hif_shutdown(struct wfx_dev *wdev); -int hif_configuration(struct wfx_dev *wdev, const u8 *conf, size_t len); -int hif_reset(struct wfx_vif *wvif, bool reset_stat); -int hif_read_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, - void *buf, size_t buf_size); -int hif_write_mib(struct wfx_dev *wdev, int vif_id, u16 mib_id, - void *buf, size_t buf_size); -int hif_scan(struct wfx_vif *wvif, struct cfg80211_scan_request *req80211, - int chan_start, int chan_num, int *timeout); -int hif_stop_scan(struct wfx_vif *wvif); -int hif_join(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, - struct ieee80211_channel *channel, const u8 *ssid, int ssidlen); -int hif_set_pm(struct wfx_vif *wvif, bool ps, int dynamic_ps_timeout); -int hif_set_bss_params(struct wfx_vif *wvif, int aid, int beacon_lost_count); -int hif_add_key(struct wfx_dev *wdev, const struct hif_req_add_key *arg); -int hif_remove_key(struct wfx_dev *wdev, int idx); -int hif_set_edca_queue_params(struct wfx_vif *wvif, u16 queue, - const struct ieee80211_tx_queue_params *arg); -int hif_start(struct wfx_vif *wvif, const struct ieee80211_bss_conf *conf, - const struct ieee80211_channel *channel); -int hif_beacon_transmit(struct wfx_vif *wvif, bool enable); -int hif_map_link(struct wfx_vif *wvif, - bool unmap, u8 *mac_addr, int sta_id, bool mfp); -int hif_update_ie_beacon(struct wfx_vif *wvif, const u8 *ies, size_t ies_len); - -#endif diff --git a/drivers/staging/wfx/hif_tx_mib.c b/drivers/staging/wfx/hif_tx_mib.c deleted file mode 100644 index 1926cf1b62be..000000000000 --- a/drivers/staging/wfx/hif_tx_mib.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (C) 2010, ST-Ericsson SA - */ - -#include - -#include "wfx.h" -#include "hif_tx.h" -#include "hif_tx_mib.h" -#include "hif_api_mib.h" - -int hif_set_output_power(struct wfx_vif *wvif, int val) -{ - struct hif_mib_current_tx_power_level arg = { - .power_level = cpu_to_le32(val * 10), - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_CURRENT_TX_POWER_LEVEL, - &arg, sizeof(arg)); -} - -int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, - unsigned int dtim_interval, - unsigned int listen_interval) -{ - struct hif_mib_beacon_wake_up_period arg = { - .wakeup_period_min = dtim_interval, - .receive_dtim = 0, - .wakeup_period_max = listen_interval, - }; - - if (dtim_interval > 0xFF || listen_interval > 0xFFFF) - return -EINVAL; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_WAKEUP_PERIOD, - &arg, sizeof(arg)); -} - -int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, - int rssi_thold, int rssi_hyst) -{ - struct hif_mib_rcpi_rssi_threshold arg = { - .rolling_average_count = 8, - .detection = 1, - }; - - if (!rssi_thold && !rssi_hyst) { - arg.upperthresh = 1; - arg.lowerthresh = 1; - } else { - arg.upper_threshold = rssi_thold + rssi_hyst; - arg.upper_threshold = (arg.upper_threshold + 110) * 2; - arg.lower_threshold = rssi_thold; - arg.lower_threshold = (arg.lower_threshold + 110) * 2; - } - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_RCPI_RSSI_THRESHOLD, &arg, sizeof(arg)); -} - -int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, - struct hif_mib_extended_count_table *arg) -{ - if (wfx_api_older_than(wdev, 1, 3)) { - // extended_count_table is wider than count_table - memset(arg, 0xFF, sizeof(*arg)); - return hif_read_mib(wdev, vif_id, HIF_MIB_ID_COUNTERS_TABLE, - arg, sizeof(struct hif_mib_count_table)); - } else { - return hif_read_mib(wdev, vif_id, - HIF_MIB_ID_EXTENDED_COUNTERS_TABLE, arg, - sizeof(struct hif_mib_extended_count_table)); - } -} - -int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac) -{ - struct hif_mib_mac_address msg = { }; - - if (mac) - ether_addr_copy(msg.mac_addr, mac); - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_DOT11_MAC_ADDRESS, - &msg, sizeof(msg)); -} - -int hif_set_rx_filter(struct wfx_vif *wvif, - bool filter_bssid, bool filter_prbreq) -{ - struct hif_mib_rx_filter arg = { }; - - if (filter_bssid) - arg.bssid_filter = 1; - if (!filter_prbreq) - arg.fwd_probe_req = 1; - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_RX_FILTER, - &arg, sizeof(arg)); -} - -int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, - const struct hif_ie_table_entry *tbl) -{ - int ret; - struct hif_mib_bcn_filter_table *arg; - int buf_len = struct_size(arg, ie_table, tbl_len); - - arg = kzalloc(buf_len, GFP_KERNEL); - if (!arg) - return -ENOMEM; - arg->num_of_info_elmts = cpu_to_le32(tbl_len); - memcpy(arg->ie_table, tbl, flex_array_size(arg, ie_table, tbl_len)); - ret = hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_FILTER_TABLE, arg, buf_len); - kfree(arg); - return ret; -} - -int hif_beacon_filter_control(struct wfx_vif *wvif, - int enable, int beacon_count) -{ - struct hif_mib_bcn_filter_enable arg = { - .enable = cpu_to_le32(enable), - .bcn_count = cpu_to_le32(beacon_count), - }; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_BEACON_FILTER_ENABLE, - &arg, sizeof(arg)); -} - -int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode) -{ - struct hif_mib_gl_operational_power_mode arg = { - .power_mode = mode, - .wup_ind_activation = 1, - }; - - return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_OPERATIONAL_POWER_MODE, - &arg, sizeof(arg)); -} - -int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, - u8 frame_type, int init_rate) -{ - struct hif_mib_template_frame *arg; - - WARN(skb->len > HIF_API_MAX_TEMPLATE_FRAME_SIZE, "frame is too big"); - skb_push(skb, 4); - arg = (struct hif_mib_template_frame *)skb->data; - skb_pull(skb, 4); - arg->init_rate = init_rate; - arg->frame_type = frame_type; - arg->frame_length = cpu_to_le16(skb->len); - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_TEMPLATE_FRAME, - arg, sizeof(*arg) + skb->len); -} - -int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required) -{ - struct hif_mib_protected_mgmt_policy arg = { }; - - WARN(required && !capable, "incoherent arguments"); - if (capable) { - arg.pmf_enable = 1; - arg.host_enc_auth_frames = 1; - } - if (!required) - arg.unpmf_allowed = 1; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_PROTECTED_MGMT_POLICY, - &arg, sizeof(arg)); -} - -int hif_set_block_ack_policy(struct wfx_vif *wvif, - u8 tx_tid_policy, u8 rx_tid_policy) -{ - struct hif_mib_block_ack_policy arg = { - .block_ack_tx_tid_policy = tx_tid_policy, - .block_ack_rx_tid_policy = rx_tid_policy, - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_BLOCK_ACK_POLICY, - &arg, sizeof(arg)); -} - -int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, - bool greenfield, bool short_preamble) -{ - struct hif_mib_set_association_mode arg = { - .preambtype_use = 1, - .mode = 1, - .spacing = 1, - .short_preamble = short_preamble, - .greenfield = greenfield, - .mpdu_start_spacing = ampdu_density, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_ASSOCIATION_MODE, &arg, sizeof(arg)); -} - -int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, - int policy_index, u8 *rates) -{ - struct hif_mib_set_tx_rate_retry_policy *arg; - size_t size = struct_size(arg, tx_rate_retry_policy, 1); - int ret; - - arg = kzalloc(size, GFP_KERNEL); - if (!arg) - return -ENOMEM; - arg->num_tx_rate_policies = 1; - arg->tx_rate_retry_policy[0].policy_index = policy_index; - arg->tx_rate_retry_policy[0].short_retry_count = 255; - arg->tx_rate_retry_policy[0].long_retry_count = 255; - arg->tx_rate_retry_policy[0].first_rate_sel = 1; - arg->tx_rate_retry_policy[0].terminate = 1; - arg->tx_rate_retry_policy[0].count_init = 1; - memcpy(&arg->tx_rate_retry_policy[0].rates, rates, - sizeof(arg->tx_rate_retry_policy[0].rates)); - ret = hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_TX_RATE_RETRY_POLICY, arg, size); - kfree(arg); - return ret; -} - -int hif_keep_alive_period(struct wfx_vif *wvif, int period) -{ - struct hif_mib_keep_alive_period arg = { - .keep_alive_period = cpu_to_le16(period), - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_KEEP_ALIVE_PERIOD, - &arg, sizeof(arg)); -}; - -int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr) -{ - struct hif_mib_arp_ip_addr_table arg = { - .condition_idx = idx, - .arp_enable = HIF_ARP_NS_FILTERING_DISABLE, - }; - - if (addr) { - // Caution: type of addr is __be32 - memcpy(arg.ipv4_address, addr, sizeof(arg.ipv4_address)); - arg.arp_enable = HIF_ARP_NS_FILTERING_ENABLE; - } - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_ARP_IP_ADDRESSES_TABLE, - &arg, sizeof(arg)); -} - -int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable) -{ - struct hif_mib_gl_set_multi_msg arg = { - .enable_multi_tx_conf = enable, - }; - - return hif_write_mib(wdev, -1, HIF_MIB_ID_GL_SET_MULTI_MSG, - &arg, sizeof(arg)); -} - -int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val) -{ - struct hif_mib_set_uapsd_information arg = { }; - - if (val & BIT(IEEE80211_AC_VO)) - arg.trig_voice = 1; - if (val & BIT(IEEE80211_AC_VI)) - arg.trig_video = 1; - if (val & BIT(IEEE80211_AC_BE)) - arg.trig_be = 1; - if (val & BIT(IEEE80211_AC_BK)) - arg.trig_bckgrnd = 1; - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_SET_UAPSD_INFORMATION, - &arg, sizeof(arg)); -} - -int hif_erp_use_protection(struct wfx_vif *wvif, bool enable) -{ - struct hif_mib_non_erp_protection arg = { - .use_cts_to_self = enable, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_NON_ERP_PROTECTION, &arg, sizeof(arg)); -} - -int hif_slot_time(struct wfx_vif *wvif, int val) -{ - struct hif_mib_slot_time arg = { - .slot_time = cpu_to_le32(val), - }; - - return hif_write_mib(wvif->wdev, wvif->id, HIF_MIB_ID_SLOT_TIME, - &arg, sizeof(arg)); -} - -int hif_wep_default_key_id(struct wfx_vif *wvif, int val) -{ - struct hif_mib_wep_default_key_id arg = { - .wep_default_key_id = val, - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_DOT11_WEP_DEFAULT_KEY_ID, - &arg, sizeof(arg)); -} - -int hif_rts_threshold(struct wfx_vif *wvif, int val) -{ - struct hif_mib_dot11_rts_threshold arg = { - .threshold = cpu_to_le32(val >= 0 ? val : 0xFFFF), - }; - - return hif_write_mib(wvif->wdev, wvif->id, - HIF_MIB_ID_DOT11_RTS_THRESHOLD, &arg, sizeof(arg)); -} diff --git a/drivers/staging/wfx/hif_tx_mib.h b/drivers/staging/wfx/hif_tx_mib.h deleted file mode 100644 index 812b3ba0f00e..000000000000 --- a/drivers/staging/wfx/hif_tx_mib.h +++ /dev/null @@ -1,49 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of host-to-chip MIBs of WFxxx Split Mac (WSM) API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (C) 2010, ST-Ericsson SA - */ -#ifndef WFX_HIF_TX_MIB_H -#define WFX_HIF_TX_MIB_H - -struct wfx_vif; -struct sk_buff; - -int hif_set_output_power(struct wfx_vif *wvif, int val); -int hif_set_beacon_wakeup_period(struct wfx_vif *wvif, - unsigned int dtim_interval, - unsigned int listen_interval); -int hif_set_rcpi_rssi_threshold(struct wfx_vif *wvif, - int rssi_thold, int rssi_hyst); -int hif_get_counters_table(struct wfx_dev *wdev, int vif_id, - struct hif_mib_extended_count_table *arg); -int hif_set_macaddr(struct wfx_vif *wvif, u8 *mac); -int hif_set_rx_filter(struct wfx_vif *wvif, - bool filter_bssid, bool fwd_probe_req); -int hif_set_beacon_filter_table(struct wfx_vif *wvif, int tbl_len, - const struct hif_ie_table_entry *tbl); -int hif_beacon_filter_control(struct wfx_vif *wvif, - int enable, int beacon_count); -int hif_set_operational_mode(struct wfx_dev *wdev, enum hif_op_power_mode mode); -int hif_set_template_frame(struct wfx_vif *wvif, struct sk_buff *skb, - u8 frame_type, int init_rate); -int hif_set_mfp(struct wfx_vif *wvif, bool capable, bool required); -int hif_set_block_ack_policy(struct wfx_vif *wvif, - u8 tx_tid_policy, u8 rx_tid_policy); -int hif_set_association_mode(struct wfx_vif *wvif, int ampdu_density, - bool greenfield, bool short_preamble); -int hif_set_tx_rate_retry_policy(struct wfx_vif *wvif, - int policy_index, u8 *rates); -int hif_keep_alive_period(struct wfx_vif *wvif, int period); -int hif_set_arp_ipv4_filter(struct wfx_vif *wvif, int idx, __be32 *addr); -int hif_use_multi_tx_conf(struct wfx_dev *wdev, bool enable); -int hif_set_uapsd_info(struct wfx_vif *wvif, unsigned long val); -int hif_erp_use_protection(struct wfx_vif *wvif, bool enable); -int hif_slot_time(struct wfx_vif *wvif, int val); -int hif_wep_default_key_id(struct wfx_vif *wvif, int val); -int hif_rts_threshold(struct wfx_vif *wvif, int val); - -#endif diff --git a/drivers/staging/wfx/hwio.c b/drivers/staging/wfx/hwio.c deleted file mode 100644 index 36fbc5b5d64c..000000000000 --- a/drivers/staging/wfx/hwio.c +++ /dev/null @@ -1,352 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Low-level I/O functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include -#include - -#include "hwio.h" -#include "wfx.h" -#include "bus.h" -#include "traces.h" - -/* - * Internal helpers. - * - * About CONFIG_VMAP_STACK: - * When CONFIG_VMAP_STACK is enabled, it is not possible to run DMA on stack - * allocated data. Functions below that work with registers (aka functions - * ending with "32") automatically reallocate buffers with kmalloc. However, - * functions that work with arbitrary length buffers let's caller to handle - * memory location. In doubt, enable CONFIG_DEBUG_SG to detect badly located - * buffer. - */ - -static int read32(struct wfx_dev *wdev, int reg, u32 *val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - *val = ~0; // Never return undefined value - if (!tmp) - return -ENOMEM; - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, - sizeof(u32)); - if (ret >= 0) - *val = le32_to_cpu(*tmp); - kfree(tmp); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -static int write32(struct wfx_dev *wdev, int reg, u32 val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - *tmp = cpu_to_le32(val); - ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, - sizeof(u32)); - kfree(tmp); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -static int read32_locked(struct wfx_dev *wdev, int reg, u32 *val) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = read32(wdev, reg, val); - _trace_io_read32(reg, *val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int write32_locked(struct wfx_dev *wdev, int reg, u32 val) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = write32(wdev, reg, val); - _trace_io_write32(reg, val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val) -{ - int ret; - u32 val_r, val_w; - - WARN_ON(~mask & val); - val &= mask; - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = read32(wdev, reg, &val_r); - _trace_io_read32(reg, val_r); - if (ret < 0) - goto err; - val_w = (val_r & ~mask) | val; - if (val_w != val_r) { - ret = write32(wdev, reg, val_w); - _trace_io_write32(reg, val_w); - } -err: - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_read(struct wfx_dev *wdev, int reg, u32 addr, - void *buf, size_t len) -{ - int ret; - int i; - u32 cfg; - u32 prefetch; - - WARN_ON(len >= 0x2000); - WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); - - if (reg == WFX_REG_AHB_DPORT) - prefetch = CFG_PREFETCH_AHB; - else if (reg == WFX_REG_SRAM_DPORT) - prefetch = CFG_PREFETCH_SRAM; - else - return -ENODEV; - - ret = write32(wdev, WFX_REG_BASE_ADDR, addr); - if (ret < 0) - goto err; - - ret = read32(wdev, WFX_REG_CONFIG, &cfg); - if (ret < 0) - goto err; - - ret = write32(wdev, WFX_REG_CONFIG, cfg | prefetch); - if (ret < 0) - goto err; - - for (i = 0; i < 20; i++) { - ret = read32(wdev, WFX_REG_CONFIG, &cfg); - if (ret < 0) - goto err; - if (!(cfg & prefetch)) - break; - usleep_range(200, 250); - } - if (i == 20) { - ret = -ETIMEDOUT; - goto err; - } - - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len); - -err: - if (ret < 0) - memset(buf, 0xFF, len); // Never return undefined value - return ret; -} - -static int indirect_write(struct wfx_dev *wdev, int reg, u32 addr, - const void *buf, size_t len) -{ - int ret; - - WARN_ON(len >= 0x2000); - WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT); - ret = write32(wdev, WFX_REG_BASE_ADDR, addr); - if (ret < 0) - return ret; - - return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len); -} - -static int indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr, - void *buf, size_t len) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_read(wdev, reg, addr, buf, len); - _trace_io_ind_read(reg, addr, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr, - const void *buf, size_t len) -{ - int ret; - - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_write(wdev, reg, addr, buf, len); - _trace_io_ind_write(reg, addr, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - return ret; -} - -static int indirect_read32_locked(struct wfx_dev *wdev, int reg, - u32 addr, u32 *val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_read(wdev, reg, addr, tmp, sizeof(u32)); - *val = le32_to_cpu(*tmp); - _trace_io_ind_read32(reg, addr, *val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - kfree(tmp); - return ret; -} - -static int indirect_write32_locked(struct wfx_dev *wdev, int reg, - u32 addr, u32 val) -{ - int ret; - __le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL); - - if (!tmp) - return -ENOMEM; - *tmp = cpu_to_le32(val); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = indirect_write(wdev, reg, addr, tmp, sizeof(u32)); - _trace_io_ind_write32(reg, addr, val); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - kfree(tmp); - return ret; -} - -int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len) -{ - int ret; - - WARN((long)buf & 3, "%s: unaligned buffer", __func__); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, - WFX_REG_IN_OUT_QUEUE, buf, len); - _trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len) -{ - int ret; - - WARN((long)buf & 3, "%s: unaligned buffer", __func__); - wdev->hwbus_ops->lock(wdev->hwbus_priv); - ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, - WFX_REG_IN_OUT_QUEUE, buf, len); - _trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len); - wdev->hwbus_ops->unlock(wdev->hwbus_priv); - if (ret) - dev_err(wdev->dev, "%s: bus communication error: %d\n", - __func__, ret); - return ret; -} - -int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) -{ - return indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); -} - -int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len) -{ - return indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); -} - -int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) -{ - return indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len); -} - -int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len) -{ - return indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len); -} - -int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) -{ - return indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); -} - -int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val) -{ - return indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); -} - -int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) -{ - return indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val); -} - -int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val) -{ - return indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val); -} - -int config_reg_read(struct wfx_dev *wdev, u32 *val) -{ - return read32_locked(wdev, WFX_REG_CONFIG, val); -} - -int config_reg_write(struct wfx_dev *wdev, u32 val) -{ - return write32_locked(wdev, WFX_REG_CONFIG, val); -} - -int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) -{ - return write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val); -} - -int control_reg_read(struct wfx_dev *wdev, u32 *val) -{ - return read32_locked(wdev, WFX_REG_CONTROL, val); -} - -int control_reg_write(struct wfx_dev *wdev, u32 val) -{ - return write32_locked(wdev, WFX_REG_CONTROL, val); -} - -int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val) -{ - return write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val); -} - -int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val) -{ - int ret; - - *val = ~0; // Never return undefined value - ret = write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24); - if (ret) - return ret; - ret = read32_locked(wdev, WFX_REG_SET_GEN_R_W, val); - if (ret) - return ret; - *val &= IGPR_VALUE; - return ret; -} - -int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val) -{ - return write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val); -} diff --git a/drivers/staging/wfx/hwio.h b/drivers/staging/wfx/hwio.h deleted file mode 100644 index 0b8e4f7157df..000000000000 --- a/drivers/staging/wfx/hwio.h +++ /dev/null @@ -1,75 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Low-level API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_HWIO_H -#define WFX_HWIO_H - -#include - -struct wfx_dev; - -int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t buf_len); -int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t buf_len); - -int sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); -int sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); - -int ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len); -int ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len); - -int sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); -int sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); - -int ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val); -int ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val); - -#define CFG_ERR_SPI_FRAME 0x00000001 // only with SPI -#define CFG_ERR_SDIO_BUF_MISMATCH 0x00000001 // only with SDIO -#define CFG_ERR_BUF_UNDERRUN 0x00000002 -#define CFG_ERR_DATA_IN_TOO_LARGE 0x00000004 -#define CFG_ERR_HOST_NO_OUT_QUEUE 0x00000008 -#define CFG_ERR_BUF_OVERRUN 0x00000010 -#define CFG_ERR_DATA_OUT_TOO_LARGE 0x00000020 -#define CFG_ERR_HOST_NO_IN_QUEUE 0x00000040 -#define CFG_ERR_HOST_CRC_MISS 0x00000080 // only with SDIO -#define CFG_SPI_IGNORE_CS 0x00000080 // only with SPI -#define CFG_BYTE_ORDER_MASK 0x00000300 // only writable with SPI -#define CFG_BYTE_ORDER_BADC 0x00000000 -#define CFG_BYTE_ORDER_DCBA 0x00000100 -#define CFG_BYTE_ORDER_ABCD 0x00000200 // SDIO always use this value -#define CFG_DIRECT_ACCESS_MODE 0x00000400 -#define CFG_PREFETCH_AHB 0x00000800 -#define CFG_DISABLE_CPU_CLK 0x00001000 -#define CFG_PREFETCH_SRAM 0x00002000 -#define CFG_CPU_RESET 0x00004000 -#define CFG_SDIO_DISABLE_IRQ 0x00008000 // only with SDIO -#define CFG_IRQ_ENABLE_DATA 0x00010000 -#define CFG_IRQ_ENABLE_WRDY 0x00020000 -#define CFG_CLK_RISE_EDGE 0x00040000 -#define CFG_SDIO_DISABLE_CRC_CHK 0x00080000 // only with SDIO -#define CFG_RESERVED 0x00F00000 -#define CFG_DEVICE_ID_MAJOR 0x07000000 -#define CFG_DEVICE_ID_RESERVED 0x78000000 -#define CFG_DEVICE_ID_TYPE 0x80000000 -int config_reg_read(struct wfx_dev *wdev, u32 *val); -int config_reg_write(struct wfx_dev *wdev, u32 val); -int config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); - -#define CTRL_NEXT_LEN_MASK 0x00000FFF -#define CTRL_WLAN_WAKEUP 0x00001000 -#define CTRL_WLAN_READY 0x00002000 -int control_reg_read(struct wfx_dev *wdev, u32 *val); -int control_reg_write(struct wfx_dev *wdev, u32 val); -int control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val); - -#define IGPR_RW 0x80000000 -#define IGPR_INDEX 0x7F000000 -#define IGPR_VALUE 0x00FFFFFF -int igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val); -int igpr_reg_write(struct wfx_dev *wdev, int index, u32 val); - -#endif /* WFX_HWIO_H */ diff --git a/drivers/staging/wfx/key.c b/drivers/staging/wfx/key.c deleted file mode 100644 index 2ab82bed4c1b..000000000000 --- a/drivers/staging/wfx/key.c +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Key management related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "key.h" -#include "wfx.h" -#include "hif_tx_mib.h" - -static int wfx_alloc_key(struct wfx_dev *wdev) -{ - int idx; - - idx = ffs(~wdev->key_map) - 1; - if (idx < 0 || idx >= MAX_KEY_ENTRIES) - return -1; - - wdev->key_map |= BIT(idx); - return idx; -} - -static void wfx_free_key(struct wfx_dev *wdev, int idx) -{ - WARN(!(wdev->key_map & BIT(idx)), "inconsistent key allocation"); - wdev->key_map &= ~BIT(idx); -} - -static u8 fill_wep_pair(struct hif_wep_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); - msg->key_length = key->keylen; - memcpy(msg->key_data, key->key, key->keylen); - ether_addr_copy(msg->peer_address, peer_addr); - return HIF_KEY_TYPE_WEP_PAIRWISE; -} - -static u8 fill_wep_group(struct hif_wep_group_key *msg, - struct ieee80211_key_conf *key) -{ - WARN(key->keylen > sizeof(msg->key_data), "inconsistent data"); - msg->key_id = key->keyidx; - msg->key_length = key->keylen; - memcpy(msg->key_data, key->key, key->keylen); - return HIF_KEY_TYPE_WEP_DEFAULT; -} - -static u8 fill_tkip_pair(struct hif_tkip_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->tkip_key_data) - + sizeof(msg->tx_mic_key) - + sizeof(msg->rx_mic_key), "inconsistent data"); - memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); - keybuf += sizeof(msg->tkip_key_data); - memcpy(msg->tx_mic_key, keybuf, sizeof(msg->tx_mic_key)); - keybuf += sizeof(msg->tx_mic_key); - memcpy(msg->rx_mic_key, keybuf, sizeof(msg->rx_mic_key)); - ether_addr_copy(msg->peer_address, peer_addr); - return HIF_KEY_TYPE_TKIP_PAIRWISE; -} - -static u8 fill_tkip_group(struct hif_tkip_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq, - enum nl80211_iftype iftype) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->tkip_key_data) - + 2 * sizeof(msg->rx_mic_key), "inconsistent data"); - msg->key_id = key->keyidx; - memcpy(msg->rx_sequence_counter, - &seq->tkip.iv16, sizeof(seq->tkip.iv16)); - memcpy(msg->rx_sequence_counter + sizeof(u16), - &seq->tkip.iv32, sizeof(seq->tkip.iv32)); - memcpy(msg->tkip_key_data, keybuf, sizeof(msg->tkip_key_data)); - keybuf += sizeof(msg->tkip_key_data); - if (iftype == NL80211_IFTYPE_AP) - // Use Tx MIC Key - memcpy(msg->rx_mic_key, keybuf + 0, sizeof(msg->rx_mic_key)); - else - // Use Rx MIC Key - memcpy(msg->rx_mic_key, keybuf + 8, sizeof(msg->rx_mic_key)); - return HIF_KEY_TYPE_TKIP_GROUP; -} - -static u8 fill_ccmp_pair(struct hif_aes_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); - ether_addr_copy(msg->peer_address, peer_addr); - memcpy(msg->aes_key_data, key->key, key->keylen); - return HIF_KEY_TYPE_AES_PAIRWISE; -} - -static u8 fill_ccmp_group(struct hif_aes_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq) -{ - WARN(key->keylen != sizeof(msg->aes_key_data), "inconsistent data"); - memcpy(msg->aes_key_data, key->key, key->keylen); - memcpy(msg->rx_sequence_counter, seq->ccmp.pn, sizeof(seq->ccmp.pn)); - memreverse(msg->rx_sequence_counter, sizeof(seq->ccmp.pn)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_AES_GROUP; -} - -static u8 fill_sms4_pair(struct hif_wapi_pairwise_key *msg, - struct ieee80211_key_conf *key, u8 *peer_addr) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->wapi_key_data) - + sizeof(msg->mic_key_data), "inconsistent data"); - ether_addr_copy(msg->peer_address, peer_addr); - memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); - keybuf += sizeof(msg->wapi_key_data); - memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_WAPI_PAIRWISE; -} - -static u8 fill_sms4_group(struct hif_wapi_group_key *msg, - struct ieee80211_key_conf *key) -{ - u8 *keybuf = key->key; - - WARN(key->keylen != sizeof(msg->wapi_key_data) - + sizeof(msg->mic_key_data), "inconsistent data"); - memcpy(msg->wapi_key_data, keybuf, sizeof(msg->wapi_key_data)); - keybuf += sizeof(msg->wapi_key_data); - memcpy(msg->mic_key_data, keybuf, sizeof(msg->mic_key_data)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_WAPI_GROUP; -} - -static u8 fill_aes_cmac_group(struct hif_igtk_group_key *msg, - struct ieee80211_key_conf *key, - struct ieee80211_key_seq *seq) -{ - WARN(key->keylen != sizeof(msg->igtk_key_data), "inconsistent data"); - memcpy(msg->igtk_key_data, key->key, key->keylen); - memcpy(msg->ipn, seq->aes_cmac.pn, sizeof(seq->aes_cmac.pn)); - memreverse(msg->ipn, sizeof(seq->aes_cmac.pn)); - msg->key_id = key->keyidx; - return HIF_KEY_TYPE_IGTK_GROUP; -} - -static int wfx_add_key(struct wfx_vif *wvif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - int ret; - struct hif_req_add_key k = { }; - struct ieee80211_key_seq seq; - struct wfx_dev *wdev = wvif->wdev; - int idx = wfx_alloc_key(wvif->wdev); - bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE; - - WARN(key->flags & IEEE80211_KEY_FLAG_PAIRWISE && !sta, "inconsistent data"); - ieee80211_get_key_rx_seq(key, 0, &seq); - if (idx < 0) - return -EINVAL; - k.int_id = wvif->id; - k.entry_index = idx; - if (key->cipher == WLAN_CIPHER_SUITE_WEP40 || - key->cipher == WLAN_CIPHER_SUITE_WEP104) { - if (pairwise) - k.type = fill_wep_pair(&k.key.wep_pairwise_key, key, - sta->addr); - else - k.type = fill_wep_group(&k.key.wep_group_key, key); - } else if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { - if (pairwise) - k.type = fill_tkip_pair(&k.key.tkip_pairwise_key, key, - sta->addr); - else - k.type = fill_tkip_group(&k.key.tkip_group_key, key, - &seq, wvif->vif->type); - } else if (key->cipher == WLAN_CIPHER_SUITE_CCMP) { - if (pairwise) - k.type = fill_ccmp_pair(&k.key.aes_pairwise_key, key, - sta->addr); - else - k.type = fill_ccmp_group(&k.key.aes_group_key, key, - &seq); - } else if (key->cipher == WLAN_CIPHER_SUITE_SMS4) { - if (pairwise) - k.type = fill_sms4_pair(&k.key.wapi_pairwise_key, key, - sta->addr); - else - k.type = fill_sms4_group(&k.key.wapi_group_key, key); - } else if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) { - k.type = fill_aes_cmac_group(&k.key.igtk_group_key, key, &seq); - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; - } else { - dev_warn(wdev->dev, "unsupported key type %d\n", key->cipher); - wfx_free_key(wdev, idx); - return -EOPNOTSUPP; - } - ret = hif_add_key(wdev, &k); - if (ret) { - wfx_free_key(wdev, idx); - return -EOPNOTSUPP; - } - key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE | - IEEE80211_KEY_FLAG_RESERVE_TAILROOM; - key->hw_key_idx = idx; - return 0; -} - -static int wfx_remove_key(struct wfx_vif *wvif, struct ieee80211_key_conf *key) -{ - WARN(key->hw_key_idx >= MAX_KEY_ENTRIES, "corrupted hw_key_idx"); - wfx_free_key(wvif->wdev, key->hw_key_idx); - return hif_remove_key(wvif->wdev, key->hw_key_idx); -} - -int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) -{ - int ret = -EOPNOTSUPP; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - mutex_lock(&wvif->wdev->conf_mutex); - if (cmd == SET_KEY) - ret = wfx_add_key(wvif, sta, key); - if (cmd == DISABLE_KEY) - ret = wfx_remove_key(wvif, key); - mutex_unlock(&wvif->wdev->conf_mutex); - return ret; -} - diff --git a/drivers/staging/wfx/key.h b/drivers/staging/wfx/key.h deleted file mode 100644 index 70a44d0ca35e..000000000000 --- a/drivers/staging/wfx/key.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_KEY_H -#define WFX_KEY_H - -#include - -struct wfx_dev; -struct wfx_vif; - -int wfx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, - struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key); - -#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/main.c b/drivers/staging/wfx/main.c deleted file mode 100644 index e7bc1988124a..000000000000 --- a/drivers/staging/wfx/main.c +++ /dev/null @@ -1,490 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Device probe and register. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2008, Johannes Berg - * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). - * Copyright (c) 2007-2009, Christian Lamparter - * Copyright (c) 2006, Michael Wu - * Copyright (c) 2004-2006 Jean-Baptiste Note , et al. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "main.h" -#include "wfx.h" -#include "fwio.h" -#include "hwio.h" -#include "bus.h" -#include "bh.h" -#include "sta.h" -#include "key.h" -#include "scan.h" -#include "debug.h" -#include "data_tx.h" -#include "hif_tx_mib.h" -#include "hif_api_cmd.h" - -#define WFX_PDS_MAX_SIZE 1500 - -MODULE_DESCRIPTION("Silicon Labs 802.11 Wireless LAN driver for WFx"); -MODULE_AUTHOR("J?r?me Pouiller "); -MODULE_LICENSE("GPL"); - -#define RATETAB_ENT(_rate, _rateid, _flags) { \ - .bitrate = (_rate), \ - .hw_value = (_rateid), \ - .flags = (_flags), \ -} - -static struct ieee80211_rate wfx_rates[] = { - RATETAB_ENT(10, 0, 0), - RATETAB_ENT(20, 1, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(55, 2, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(110, 3, IEEE80211_RATE_SHORT_PREAMBLE), - RATETAB_ENT(60, 6, 0), - RATETAB_ENT(90, 7, 0), - RATETAB_ENT(120, 8, 0), - RATETAB_ENT(180, 9, 0), - RATETAB_ENT(240, 10, 0), - RATETAB_ENT(360, 11, 0), - RATETAB_ENT(480, 12, 0), - RATETAB_ENT(540, 13, 0), -}; - -#define CHAN2G(_channel, _freq, _flags) { \ - .band = NL80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -static struct ieee80211_channel wfx_2ghz_chantable[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static const struct ieee80211_supported_band wfx_band_2ghz = { - .channels = wfx_2ghz_chantable, - .n_channels = ARRAY_SIZE(wfx_2ghz_chantable), - .bitrates = wfx_rates, - .n_bitrates = ARRAY_SIZE(wfx_rates), - .ht_cap = { - // Receive caps - .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_MAX_AMSDU | - (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), - .ht_supported = 1, - .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, - .ampdu_density = IEEE80211_HT_MPDU_DENSITY_NONE, - .mcs = { - .rx_mask = { 0xFF }, // MCS0 to MCS7 - .rx_highest = cpu_to_le16(72), - .tx_params = IEEE80211_HT_MCS_TX_DEFINED, - }, - }, -}; - -static const struct ieee80211_iface_limit wdev_iface_limits[] = { - { .max = 1, .types = BIT(NL80211_IFTYPE_STATION) }, - { .max = 1, .types = BIT(NL80211_IFTYPE_AP) }, -}; - -static const struct ieee80211_iface_combination wfx_iface_combinations[] = { - { - .num_different_channels = 2, - .max_interfaces = 2, - .limits = wdev_iface_limits, - .n_limits = ARRAY_SIZE(wdev_iface_limits), - } -}; - -static const struct ieee80211_ops wfx_ops = { - .start = wfx_start, - .stop = wfx_stop, - .add_interface = wfx_add_interface, - .remove_interface = wfx_remove_interface, - .config = wfx_config, - .tx = wfx_tx, - .join_ibss = wfx_join_ibss, - .leave_ibss = wfx_leave_ibss, - .conf_tx = wfx_conf_tx, - .hw_scan = wfx_hw_scan, - .cancel_hw_scan = wfx_cancel_hw_scan, - .start_ap = wfx_start_ap, - .stop_ap = wfx_stop_ap, - .sta_add = wfx_sta_add, - .sta_remove = wfx_sta_remove, - .set_tim = wfx_set_tim, - .set_key = wfx_set_key, - .set_rts_threshold = wfx_set_rts_threshold, - .set_default_unicast_key = wfx_set_default_unicast_key, - .bss_info_changed = wfx_bss_info_changed, - .configure_filter = wfx_configure_filter, - .ampdu_action = wfx_ampdu_action, - .flush = wfx_flush, - .add_chanctx = wfx_add_chanctx, - .remove_chanctx = wfx_remove_chanctx, - .change_chanctx = wfx_change_chanctx, - .assign_vif_chanctx = wfx_assign_vif_chanctx, - .unassign_vif_chanctx = wfx_unassign_vif_chanctx, -}; - -bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor) -{ - if (wdev->hw_caps.api_version_major < major) - return true; - if (wdev->hw_caps.api_version_major > major) - return false; - if (wdev->hw_caps.api_version_minor < minor) - return true; - return false; -} - -/* NOTE: wfx_send_pds() destroy buf */ -int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len) -{ - int ret; - int start, brace_level, i; - - start = 0; - brace_level = 0; - if (buf[0] != '{') { - dev_err(wdev->dev, "valid PDS start with '{'. Did you forget to compress it?\n"); - return -EINVAL; - } - for (i = 1; i < len - 1; i++) { - if (buf[i] == '{') - brace_level++; - if (buf[i] == '}') - brace_level--; - if (buf[i] == '}' && !brace_level) { - i++; - if (i - start + 1 > WFX_PDS_MAX_SIZE) - return -EFBIG; - buf[start] = '{'; - buf[i] = 0; - dev_dbg(wdev->dev, "send PDS '%s}'\n", buf + start); - buf[i] = '}'; - ret = hif_configuration(wdev, buf + start, - i - start + 1); - if (ret > 0) { - dev_err(wdev->dev, "PDS bytes %d to %d: invalid data (unsupported options?)\n", - start, i); - return -EINVAL; - } - if (ret == -ETIMEDOUT) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip didn't reply (corrupted file?)\n", - start, i); - return ret; - } - if (ret) { - dev_err(wdev->dev, "PDS bytes %d to %d: chip returned an unknown error\n", - start, i); - return -EIO; - } - buf[i] = ','; - start = i; - } - } - return 0; -} - -static int wfx_send_pdata_pds(struct wfx_dev *wdev) -{ - int ret = 0; - const struct firmware *pds; - u8 *tmp_buf; - - ret = request_firmware(&pds, wdev->pdata.file_pds, wdev->dev); - if (ret) { - dev_err(wdev->dev, "can't load PDS file %s\n", - wdev->pdata.file_pds); - goto err1; - } - tmp_buf = kmemdup(pds->data, pds->size, GFP_KERNEL); - if (!tmp_buf) { - ret = -ENOMEM; - goto err2; - } - ret = wfx_send_pds(wdev, tmp_buf, pds->size); - kfree(tmp_buf); -err2: - release_firmware(pds); -err1: - return ret; -} - -static void wfx_free_common(void *data) -{ - struct wfx_dev *wdev = data; - - mutex_destroy(&wdev->tx_power_loop_info_lock); - mutex_destroy(&wdev->rx_stats_lock); - mutex_destroy(&wdev->conf_mutex); - ieee80211_free_hw(wdev->hw); -} - -struct wfx_dev *wfx_init_common(struct device *dev, - const struct wfx_platform_data *pdata, - const struct hwbus_ops *hwbus_ops, - void *hwbus_priv) -{ - struct ieee80211_hw *hw; - struct wfx_dev *wdev; - - hw = ieee80211_alloc_hw(sizeof(struct wfx_dev), &wfx_ops); - if (!hw) - return NULL; - - SET_IEEE80211_DEV(hw, dev); - - ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(hw, AMPDU_AGGREGATION); - ieee80211_hw_set(hw, CONNECTION_MONITOR); - ieee80211_hw_set(hw, REPORTS_TX_ACK_STATUS); - ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); - ieee80211_hw_set(hw, SIGNAL_DBM); - ieee80211_hw_set(hw, SUPPORTS_PS); - ieee80211_hw_set(hw, MFP_CAPABLE); - - hw->vif_data_size = sizeof(struct wfx_vif); - hw->sta_data_size = sizeof(struct wfx_sta_priv); - hw->queues = 4; - hw->max_rates = 8; - hw->max_rate_tries = 8; - hw->extra_tx_headroom = sizeof(struct hif_msg) - + sizeof(struct hif_req_tx) - + 4 /* alignment */ + 8 /* TKIP IV */; - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); - hw->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; - hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; - hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; - hw->wiphy->max_ap_assoc_sta = HIF_LINK_ID_MAX; - hw->wiphy->max_scan_ssids = 2; - hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN; - hw->wiphy->n_iface_combinations = ARRAY_SIZE(wfx_iface_combinations); - hw->wiphy->iface_combinations = wfx_iface_combinations; - hw->wiphy->bands[NL80211_BAND_2GHZ] = devm_kmalloc(dev, sizeof(wfx_band_2ghz), GFP_KERNEL); - // FIXME: also copy wfx_rates and wfx_2ghz_chantable - memcpy(hw->wiphy->bands[NL80211_BAND_2GHZ], &wfx_band_2ghz, - sizeof(wfx_band_2ghz)); - - wdev = hw->priv; - wdev->hw = hw; - wdev->dev = dev; - wdev->hwbus_ops = hwbus_ops; - wdev->hwbus_priv = hwbus_priv; - memcpy(&wdev->pdata, pdata, sizeof(*pdata)); - of_property_read_string(dev->of_node, "config-file", - &wdev->pdata.file_pds); - wdev->pdata.gpio_wakeup = devm_gpiod_get_optional(dev, "wakeup", - GPIOD_OUT_LOW); - if (IS_ERR(wdev->pdata.gpio_wakeup)) - return NULL; - if (wdev->pdata.gpio_wakeup) - gpiod_set_consumer_name(wdev->pdata.gpio_wakeup, "wfx wakeup"); - - mutex_init(&wdev->conf_mutex); - mutex_init(&wdev->rx_stats_lock); - mutex_init(&wdev->tx_power_loop_info_lock); - init_completion(&wdev->firmware_ready); - INIT_DELAYED_WORK(&wdev->cooling_timeout_work, - wfx_cooling_timeout_work); - skb_queue_head_init(&wdev->tx_pending); - init_waitqueue_head(&wdev->tx_dequeue); - wfx_init_hif_cmd(&wdev->hif_cmd); - wdev->force_ps_timeout = -1; - - if (devm_add_action_or_reset(dev, wfx_free_common, wdev)) - return NULL; - - return wdev; -} - -int wfx_probe(struct wfx_dev *wdev) -{ - int i; - int err; - const void *macaddr; - struct gpio_desc *gpio_saved; - - // During first part of boot, gpio_wakeup cannot yet been used. So - // prevent bh() to touch it. - gpio_saved = wdev->pdata.gpio_wakeup; - wdev->pdata.gpio_wakeup = NULL; - wdev->poll_irq = true; - - wfx_bh_register(wdev); - - err = wfx_init_device(wdev); - if (err) - goto err0; - - wfx_bh_poll_irq(wdev); - err = wait_for_completion_timeout(&wdev->firmware_ready, 1 * HZ); - if (err <= 0) { - if (err == 0) { - dev_err(wdev->dev, "timeout while waiting for startup indication\n"); - err = -ETIMEDOUT; - } else if (err == -ERESTARTSYS) { - dev_info(wdev->dev, "probe interrupted by user\n"); - } - goto err0; - } - - // FIXME: fill wiphy::hw_version - dev_info(wdev->dev, "started firmware %d.%d.%d \"%s\" (API: %d.%d, keyset: %02X, caps: 0x%.8X)\n", - wdev->hw_caps.firmware_major, wdev->hw_caps.firmware_minor, - wdev->hw_caps.firmware_build, wdev->hw_caps.firmware_label, - wdev->hw_caps.api_version_major, wdev->hw_caps.api_version_minor, - wdev->keyset, wdev->hw_caps.link_mode); - snprintf(wdev->hw->wiphy->fw_version, - sizeof(wdev->hw->wiphy->fw_version), - "%d.%d.%d", - wdev->hw_caps.firmware_major, - wdev->hw_caps.firmware_minor, - wdev->hw_caps.firmware_build); - - if (wfx_api_older_than(wdev, 1, 0)) { - dev_err(wdev->dev, - "unsupported firmware API version (expect 1 while firmware returns %d)\n", - wdev->hw_caps.api_version_major); - err = -ENOTSUPP; - goto err0; - } - - if (wdev->hw_caps.link_mode == SEC_LINK_ENFORCED) { - dev_err(wdev->dev, - "chip require secure_link, but can't negotiate it\n"); - goto err0; - } - - if (wdev->hw_caps.region_sel_mode) { - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[11].flags |= IEEE80211_CHAN_NO_IR; - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[12].flags |= IEEE80211_CHAN_NO_IR; - wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[13].flags |= IEEE80211_CHAN_DISABLED; - } - - dev_dbg(wdev->dev, "sending configuration file %s\n", - wdev->pdata.file_pds); - err = wfx_send_pdata_pds(wdev); - if (err < 0) - goto err0; - - wdev->poll_irq = false; - err = wdev->hwbus_ops->irq_subscribe(wdev->hwbus_priv); - if (err) - goto err0; - - err = hif_use_multi_tx_conf(wdev, true); - if (err) - dev_err(wdev->dev, "misconfigured IRQ?\n"); - - wdev->pdata.gpio_wakeup = gpio_saved; - if (wdev->pdata.gpio_wakeup) { - dev_dbg(wdev->dev, - "enable 'quiescent' power mode with wakeup GPIO and PDS file %s\n", - wdev->pdata.file_pds); - gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); - control_reg_write(wdev, 0); - hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_QUIESCENT); - } else { - hif_set_operational_mode(wdev, HIF_OP_POWER_MODE_DOZE); - } - - for (i = 0; i < ARRAY_SIZE(wdev->addresses); i++) { - eth_zero_addr(wdev->addresses[i].addr); - macaddr = of_get_mac_address(wdev->dev->of_node); - if (!IS_ERR_OR_NULL(macaddr)) { - ether_addr_copy(wdev->addresses[i].addr, macaddr); - wdev->addresses[i].addr[ETH_ALEN - 1] += i; - } else { - ether_addr_copy(wdev->addresses[i].addr, - wdev->hw_caps.mac_addr[i]); - } - if (!is_valid_ether_addr(wdev->addresses[i].addr)) { - dev_warn(wdev->dev, "using random MAC address\n"); - eth_random_addr(wdev->addresses[i].addr); - } - dev_info(wdev->dev, "MAC address %d: %pM\n", i, - wdev->addresses[i].addr); - } - wdev->hw->wiphy->n_addresses = ARRAY_SIZE(wdev->addresses); - wdev->hw->wiphy->addresses = wdev->addresses; - - err = ieee80211_register_hw(wdev->hw); - if (err) - goto err1; - - err = wfx_debug_init(wdev); - if (err) - goto err2; - - return 0; - -err2: - ieee80211_unregister_hw(wdev->hw); -err1: - wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); -err0: - wfx_bh_unregister(wdev); - return err; -} - -void wfx_release(struct wfx_dev *wdev) -{ - ieee80211_unregister_hw(wdev->hw); - hif_shutdown(wdev); - wdev->hwbus_ops->irq_unsubscribe(wdev->hwbus_priv); - wfx_bh_unregister(wdev); -} - -static int __init wfx_core_init(void) -{ - int ret = 0; - - if (IS_ENABLED(CONFIG_SPI)) - ret = spi_register_driver(&wfx_spi_driver); - if (IS_ENABLED(CONFIG_MMC) && !ret) - ret = sdio_register_driver(&wfx_sdio_driver); - return ret; -} -module_init(wfx_core_init); - -static void __exit wfx_core_exit(void) -{ - if (IS_ENABLED(CONFIG_MMC)) - sdio_unregister_driver(&wfx_sdio_driver); - if (IS_ENABLED(CONFIG_SPI)) - spi_unregister_driver(&wfx_spi_driver); -} -module_exit(wfx_core_exit); diff --git a/drivers/staging/wfx/main.h b/drivers/staging/wfx/main.h deleted file mode 100644 index a0db322383a3..000000000000 --- a/drivers/staging/wfx/main.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Device probe and register. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2006, Michael Wu - * Copyright 2004-2006 Jean-Baptiste Note , et al. - */ -#ifndef WFX_MAIN_H -#define WFX_MAIN_H - -#include -#include - -#include "hif_api_general.h" - -struct wfx_dev; -struct hwbus_ops; - -struct wfx_platform_data { - /* Keyset and ".sec" extension will be appended to this string */ - const char *file_fw; - const char *file_pds; - struct gpio_desc *gpio_wakeup; - /* - * if true HIF D_out is sampled on the rising edge of the clock - * (intended to be used in 50Mhz SDIO) - */ - bool use_rising_clk; -}; - -struct wfx_dev *wfx_init_common(struct device *dev, - const struct wfx_platform_data *pdata, - const struct hwbus_ops *hwbus_ops, - void *hwbus_priv); - -int wfx_probe(struct wfx_dev *wdev); -void wfx_release(struct wfx_dev *wdev); - -bool wfx_api_older_than(struct wfx_dev *wdev, int major, int minor); -int wfx_send_pds(struct wfx_dev *wdev, u8 *buf, size_t len); - -#endif diff --git a/drivers/staging/wfx/queue.c b/drivers/staging/wfx/queue.c deleted file mode 100644 index 31c37f69c295..000000000000 --- a/drivers/staging/wfx/queue.c +++ /dev/null @@ -1,304 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * O(1) TX queue with built-in allocator. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "queue.h" -#include "wfx.h" -#include "sta.h" -#include "data_tx.h" -#include "traces.h" - -void wfx_tx_lock(struct wfx_dev *wdev) -{ - atomic_inc(&wdev->tx_lock); -} - -void wfx_tx_unlock(struct wfx_dev *wdev) -{ - int tx_lock = atomic_dec_return(&wdev->tx_lock); - - WARN(tx_lock < 0, "inconsistent tx_lock value"); - if (!tx_lock) - wfx_bh_request_tx(wdev); -} - -void wfx_tx_flush(struct wfx_dev *wdev) -{ - int ret; - - // Do not wait for any reply if chip is frozen - if (wdev->chip_frozen) - return; - - wfx_tx_lock(wdev); - mutex_lock(&wdev->hif_cmd.lock); - ret = wait_event_timeout(wdev->hif.tx_buffers_empty, - !wdev->hif.tx_buffers_used, - msecs_to_jiffies(3000)); - if (!ret) { - dev_warn(wdev->dev, "cannot flush tx buffers (%d still busy)\n", - wdev->hif.tx_buffers_used); - wfx_pending_dump_old_frames(wdev, 3000); - // FIXME: drop pending frames here - wdev->chip_frozen = true; - } - mutex_unlock(&wdev->hif_cmd.lock); - wfx_tx_unlock(wdev); -} - -void wfx_tx_lock_flush(struct wfx_dev *wdev) -{ - wfx_tx_lock(wdev); - wfx_tx_flush(wdev); -} - -void wfx_tx_queues_init(struct wfx_vif *wvif) -{ - // The device is in charge to respect the details of the QoS parameters. - // The driver just ensure that it roughtly respect the priorities to - // avoid any shortage. - const int priorities[IEEE80211_NUM_ACS] = { 1, 2, 64, 128 }; - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - skb_queue_head_init(&wvif->tx_queue[i].normal); - skb_queue_head_init(&wvif->tx_queue[i].cab); - wvif->tx_queue[i].priority = priorities[i]; - } -} - -void wfx_tx_queues_check_empty(struct wfx_vif *wvif) -{ - int i; - - for (i = 0; i < IEEE80211_NUM_ACS; ++i) { - WARN_ON(atomic_read(&wvif->tx_queue[i].pending_frames)); - WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].normal)); - WARN_ON(!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)); - } -} - -bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue) -{ - return skb_queue_empty(&queue->normal) && skb_queue_empty(&queue->cab); -} - -static void __wfx_tx_queue_drop(struct wfx_vif *wvif, - struct sk_buff_head *skb_queue, - struct sk_buff_head *dropped) -{ - struct sk_buff *skb, *tmp; - - spin_lock_bh(&skb_queue->lock); - skb_queue_walk_safe(skb_queue, skb, tmp) { - __skb_unlink(skb, skb_queue); - skb_queue_head(dropped, skb); - } - spin_unlock_bh(&skb_queue->lock); -} - -void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, - struct sk_buff_head *dropped) -{ - __wfx_tx_queue_drop(wvif, &queue->cab, dropped); - __wfx_tx_queue_drop(wvif, &queue->normal, dropped); - wake_up(&wvif->wdev->tx_dequeue); -} - -void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb) -{ - struct wfx_queue *queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - skb_queue_tail(&queue->cab, skb); - else - skb_queue_tail(&queue->normal, skb); -} - -void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped) -{ - struct wfx_queue *queue; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - WARN(!wdev->chip_frozen, "%s should only be used to recover a frozen device", - __func__); - while ((skb = skb_dequeue(&wdev->tx_pending)) != NULL) { - hif = (struct hif_msg *)skb->data; - wvif = wdev_to_wvif(wdev, hif->interface); - if (wvif) { - queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - WARN_ON(skb_get_queue_mapping(skb) > 3); - WARN_ON(!atomic_read(&queue->pending_frames)); - atomic_dec(&queue->pending_frames); - } - skb_queue_head(dropped, skb); - } -} - -struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id) -{ - struct wfx_queue *queue; - struct hif_req_tx *req; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - spin_lock_bh(&wdev->tx_pending.lock); - skb_queue_walk(&wdev->tx_pending, skb) { - hif = (struct hif_msg *)skb->data; - req = (struct hif_req_tx *)hif->body; - if (req->packet_id != packet_id) - continue; - spin_unlock_bh(&wdev->tx_pending.lock); - wvif = wdev_to_wvif(wdev, hif->interface); - if (wvif) { - queue = &wvif->tx_queue[skb_get_queue_mapping(skb)]; - WARN_ON(skb_get_queue_mapping(skb) > 3); - WARN_ON(!atomic_read(&queue->pending_frames)); - atomic_dec(&queue->pending_frames); - } - skb_unlink(skb, &wdev->tx_pending); - return skb; - } - spin_unlock_bh(&wdev->tx_pending.lock); - WARN(1, "cannot find packet in pending queue"); - return NULL; -} - -void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms) -{ - ktime_t now = ktime_get(); - struct wfx_tx_priv *tx_priv; - struct hif_req_tx *req; - struct sk_buff *skb; - bool first = true; - - spin_lock_bh(&wdev->tx_pending.lock); - skb_queue_walk(&wdev->tx_pending, skb) { - tx_priv = wfx_skb_tx_priv(skb); - req = wfx_skb_txreq(skb); - if (ktime_after(now, ktime_add_ms(tx_priv->xmit_timestamp, - limit_ms))) { - if (first) { - dev_info(wdev->dev, "frames stuck in firmware since %dms or more:\n", - limit_ms); - first = false; - } - dev_info(wdev->dev, " id %08x sent %lldms ago\n", - req->packet_id, - ktime_ms_delta(now, tx_priv->xmit_timestamp)); - } - } - spin_unlock_bh(&wdev->tx_pending.lock); -} - -unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, - struct sk_buff *skb) -{ - ktime_t now = ktime_get(); - struct wfx_tx_priv *tx_priv = wfx_skb_tx_priv(skb); - - return ktime_us_delta(now, tx_priv->xmit_timestamp); -} - -bool wfx_tx_queues_has_cab(struct wfx_vif *wvif) -{ - int i; - - if (wvif->vif->type != NL80211_IFTYPE_AP) - return false; - for (i = 0; i < IEEE80211_NUM_ACS; ++i) - // Note: since only AP can have mcast frames in queue and only - // one vif can be AP, all queued frames has same interface id - if (!skb_queue_empty_lockless(&wvif->tx_queue[i].cab)) - return true; - return false; -} - -static int wfx_tx_queue_get_weight(struct wfx_queue *queue) -{ - return atomic_read(&queue->pending_frames) * queue->priority; -} - -static struct sk_buff *wfx_tx_queues_get_skb(struct wfx_dev *wdev) -{ - struct wfx_queue *queues[IEEE80211_NUM_ACS * ARRAY_SIZE(wdev->vif)]; - int i, j, num_queues = 0; - struct wfx_vif *wvif; - struct hif_msg *hif; - struct sk_buff *skb; - - // sort the queues - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - WARN_ON(num_queues >= ARRAY_SIZE(queues)); - queues[num_queues] = &wvif->tx_queue[i]; - for (j = num_queues; j > 0; j--) - if (wfx_tx_queue_get_weight(queues[j]) < - wfx_tx_queue_get_weight(queues[j - 1])) - swap(queues[j - 1], queues[j]); - num_queues++; - } - } - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - if (!wvif->after_dtim_tx_allowed) - continue; - for (i = 0; i < num_queues; i++) { - skb = skb_dequeue(&queues[i]->cab); - if (!skb) - continue; - // Note: since only AP can have mcast frames in queue - // and only one vif can be AP, all queued frames has - // same interface id - hif = (struct hif_msg *)skb->data; - WARN_ON(hif->interface != wvif->id); - WARN_ON(queues[i] != - &wvif->tx_queue[skb_get_queue_mapping(skb)]); - atomic_inc(&queues[i]->pending_frames); - trace_queues_stats(wdev, queues[i]); - return skb; - } - // No more multicast to sent - wvif->after_dtim_tx_allowed = false; - schedule_work(&wvif->update_tim_work); - } - - for (i = 0; i < num_queues; i++) { - skb = skb_dequeue(&queues[i]->normal); - if (skb) { - atomic_inc(&queues[i]->pending_frames); - trace_queues_stats(wdev, queues[i]); - return skb; - } - } - return NULL; -} - -struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev) -{ - struct wfx_tx_priv *tx_priv; - struct sk_buff *skb; - - if (atomic_read(&wdev->tx_lock)) - return NULL; - skb = wfx_tx_queues_get_skb(wdev); - if (!skb) - return NULL; - skb_queue_tail(&wdev->tx_pending, skb); - wake_up(&wdev->tx_dequeue); - tx_priv = wfx_skb_tx_priv(skb); - tx_priv->xmit_timestamp = ktime_get(); - return (struct hif_msg *)skb->data; -} diff --git a/drivers/staging/wfx/queue.h b/drivers/staging/wfx/queue.h deleted file mode 100644 index 80ba19455ef3..000000000000 --- a/drivers/staging/wfx/queue.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * O(1) TX queue with built-in allocator. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_QUEUE_H -#define WFX_QUEUE_H - -#include -#include - -struct wfx_dev; -struct wfx_vif; - -struct wfx_queue { - struct sk_buff_head normal; - struct sk_buff_head cab; // Content After (DTIM) Beacon - atomic_t pending_frames; - int priority; -}; - -void wfx_tx_lock(struct wfx_dev *wdev); -void wfx_tx_unlock(struct wfx_dev *wdev); -void wfx_tx_flush(struct wfx_dev *wdev); -void wfx_tx_lock_flush(struct wfx_dev *wdev); - -void wfx_tx_queues_init(struct wfx_vif *wvif); -void wfx_tx_queues_check_empty(struct wfx_vif *wvif); -bool wfx_tx_queues_has_cab(struct wfx_vif *wvif); -void wfx_tx_queues_put(struct wfx_vif *wvif, struct sk_buff *skb); -struct hif_msg *wfx_tx_queues_get(struct wfx_dev *wdev); - -bool wfx_tx_queue_empty(struct wfx_vif *wvif, struct wfx_queue *queue); -void wfx_tx_queue_drop(struct wfx_vif *wvif, struct wfx_queue *queue, - struct sk_buff_head *dropped); - -struct sk_buff *wfx_pending_get(struct wfx_dev *wdev, u32 packet_id); -void wfx_pending_drop(struct wfx_dev *wdev, struct sk_buff_head *dropped); -unsigned int wfx_pending_get_pkt_us_delay(struct wfx_dev *wdev, - struct sk_buff *skb); -void wfx_pending_dump_old_frames(struct wfx_dev *wdev, unsigned int limit_ms); - -#endif /* WFX_QUEUE_H */ diff --git a/drivers/staging/wfx/scan.c b/drivers/staging/wfx/scan.c deleted file mode 100644 index fb47c7cddf2f..000000000000 --- a/drivers/staging/wfx/scan.c +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Scan related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include - -#include "scan.h" -#include "wfx.h" -#include "sta.h" -#include "hif_tx_mib.h" - -static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, - bool aborted) -{ - struct cfg80211_scan_info info = { - .aborted = aborted, - }; - - ieee80211_scan_completed(hw, &info); -} - -static int update_probe_tmpl(struct wfx_vif *wvif, - struct cfg80211_scan_request *req) -{ - struct sk_buff *skb; - - skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr, - NULL, 0, req->ie_len); - if (!skb) - return -ENOMEM; - - skb_put_data(skb, req->ie, req->ie_len); - hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0); - dev_kfree_skb(skb); - return 0; -} - -static int send_scan_req(struct wfx_vif *wvif, - struct cfg80211_scan_request *req, int start_idx) -{ - int i, ret, timeout; - struct ieee80211_channel *ch_start, *ch_cur; - - for (i = start_idx; i < req->n_channels; i++) { - ch_start = req->channels[start_idx]; - ch_cur = req->channels[i]; - WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported"); - if (ch_cur->max_power != ch_start->max_power) - break; - if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR) - break; - } - wfx_tx_lock_flush(wvif->wdev); - wvif->scan_abort = false; - reinit_completion(&wvif->scan_complete); - ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout); - if (ret) { - wfx_tx_unlock(wvif->wdev); - return -EIO; - } - ret = wait_for_completion_timeout(&wvif->scan_complete, timeout); - if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower) - hif_set_output_power(wvif, wvif->vif->bss_conf.txpower); - wfx_tx_unlock(wvif->wdev); - if (!ret) { - dev_notice(wvif->wdev->dev, "scan timeout\n"); - hif_stop_scan(wvif); - return -ETIMEDOUT; - } - if (wvif->scan_abort) { - dev_notice(wvif->wdev->dev, "scan abort\n"); - return -ECONNABORTED; - } - return i - start_idx; -} - -/* - * It is not really necessary to run scan request asynchronously. However, - * there is a bug in "iw scan" when ieee80211_scan_completed() is called before - * wfx_hw_scan() return - */ -void wfx_hw_scan_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work); - struct ieee80211_scan_request *hw_req = wvif->scan_req; - int chan_cur, ret; - - mutex_lock(&wvif->wdev->conf_mutex); - mutex_lock(&wvif->scan_lock); - if (wvif->join_in_progress) { - dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN", - __func__); - wfx_reset(wvif); - } - update_probe_tmpl(wvif, &hw_req->req); - chan_cur = 0; - do { - ret = send_scan_req(wvif, &hw_req->req, chan_cur); - if (ret > 0) - chan_cur += ret; - } while (ret > 0 && chan_cur < hw_req->req.n_channels); - mutex_unlock(&wvif->scan_lock); - mutex_unlock(&wvif->wdev->conf_mutex); - __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0); -} - -int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS); - wvif->scan_req = hw_req; - schedule_work(&wvif->scan_work); - return 0; -} - -void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wvif->scan_abort = true; - hif_stop_scan(wvif); -} - -void wfx_scan_complete(struct wfx_vif *wvif) -{ - complete(&wvif->scan_complete); -} diff --git a/drivers/staging/wfx/scan.h b/drivers/staging/wfx/scan.h deleted file mode 100644 index c7496a766478..000000000000 --- a/drivers/staging/wfx/scan.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Scan related functions. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_SCAN_H -#define WFX_SCAN_H - -#include - -struct wfx_dev; -struct wfx_vif; - -void wfx_hw_scan_work(struct work_struct *work); -int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_scan_request *req); -void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_scan_complete(struct wfx_vif *wvif); - -#endif /* WFX_SCAN_H */ diff --git a/drivers/staging/wfx/sta.c b/drivers/staging/wfx/sta.c deleted file mode 100644 index 196779a1b89a..000000000000 --- a/drivers/staging/wfx/sta.c +++ /dev/null @@ -1,807 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#include -#include - -#include "sta.h" -#include "wfx.h" -#include "fwio.h" -#include "bh.h" -#include "key.h" -#include "scan.h" -#include "debug.h" -#include "hif_tx.h" -#include "hif_tx_mib.h" - -#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2 - -u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) -{ - int i; - u32 ret = 0; - // WFx only support 2GHz - struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; - - for (i = 0; i < sband->n_bitrates; i++) { - if (rates & BIT(i)) { - if (i >= sband->n_bitrates) - dev_warn(wdev->dev, "unsupported basic rate\n"); - else - ret |= BIT(sband->bitrates[i].hw_value); - } - } - return ret; -} - -void wfx_cooling_timeout_work(struct work_struct *work) -{ - struct wfx_dev *wdev = container_of(to_delayed_work(work), - struct wfx_dev, - cooling_timeout_work); - - wdev->chip_frozen = true; - wfx_tx_unlock(wdev); -} - -void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) -{ - if (cmd == STA_NOTIFY_AWAKE) { - // Device recover normal temperature - if (cancel_delayed_work(&wdev->cooling_timeout_work)) - wfx_tx_unlock(wdev); - } else { - // Device is too hot - schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); - wfx_tx_lock(wdev); - } -} - -static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) -{ - static const struct hif_ie_table_entry filter_ies[] = { - { - .ie_id = WLAN_EID_VENDOR_SPECIFIC, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - .oui = { 0x50, 0x6F, 0x9A }, - }, { - .ie_id = WLAN_EID_HT_OPERATION, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - }, { - .ie_id = WLAN_EID_ERP_INFO, - .has_changed = 1, - .no_longer = 1, - .has_appeared = 1, - } - }; - - if (!filter_beacon) { - hif_beacon_filter_control(wvif, 0, 1); - } else { - hif_set_beacon_filter_table(wvif, 3, filter_ies); - hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); - } -} - -void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, u64 unused) -{ - struct wfx_vif *wvif = NULL; - struct wfx_dev *wdev = hw->priv; - bool filter_bssid, filter_prbreq, filter_beacon; - - // Notes: - // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered - // - PS-Poll (FIF_PSPOLL) are never filtered - // - RTS, CTS and Ack (FIF_CONTROL) are always filtered - // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered - // - Firmware does (yet) allow to forward unicast traffic sent to - // other stations (aka. promiscuous mode) - *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS | - FIF_PROBE_REQ | FIF_PSPOLL; - - mutex_lock(&wdev->conf_mutex); - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - mutex_lock(&wvif->scan_lock); - - // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and - // beacons from other BSS - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - filter_beacon = false; - else - filter_beacon = true; - wfx_filter_beacon(wvif, filter_beacon); - - if (*total_flags & FIF_OTHER_BSS) - filter_bssid = false; - else - filter_bssid = true; - - // In AP mode, chip can reply to probe request itself - if (*total_flags & FIF_PROBE_REQ && - wvif->vif->type == NL80211_IFTYPE_AP) { - dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); - *total_flags &= ~FIF_PROBE_REQ; - } - - if (*total_flags & FIF_PROBE_REQ) - filter_prbreq = false; - else - filter_prbreq = true; - hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); - - mutex_unlock(&wvif->scan_lock); - } - mutex_unlock(&wdev->conf_mutex); -} - -static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) -{ - struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; - struct ieee80211_conf *conf = &wvif->wdev->hw->conf; - - WARN(!wvif->vif->bss_conf.assoc && enable_ps, - "enable_ps is reliable only if associated"); - if (wdev_to_wvif(wvif->wdev, 0)) - chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan; - if (wdev_to_wvif(wvif->wdev, 1)) - chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan; - if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && - wvif->vif->type != NL80211_IFTYPE_AP) { - // It is necessary to enable powersave if channels - // are different. - if (enable_ps) - *enable_ps = true; - if (wvif->wdev->force_ps_timeout > -1) - return wvif->wdev->force_ps_timeout; - else if (wfx_api_older_than(wvif->wdev, 3, 2)) - return 0; - else - return 30; - } - if (enable_ps) - *enable_ps = wvif->vif->bss_conf.ps; - if (wvif->wdev->force_ps_timeout > -1) - return wvif->wdev->force_ps_timeout; - else if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps) - return conf->dynamic_ps_timeout; - else - return -1; -} - -int wfx_update_pm(struct wfx_vif *wvif) -{ - int ps_timeout; - bool ps; - - if (!wvif->vif->bss_conf.assoc) - return 0; - ps_timeout = wfx_get_ps_timeout(wvif, &ps); - if (!ps) - ps_timeout = 0; - WARN_ON(ps_timeout < 0); - if (wvif->uapsd_mask) - ps_timeout = 0; - - if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, - TU_TO_JIFFIES(512))) - dev_warn(wvif->wdev->dev, - "timeout while waiting of set_pm_mode_complete\n"); - return hif_set_pm(wvif, ps, ps_timeout); -} - -int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - int old_uapsd = wvif->uapsd_mask; - - WARN_ON(queue >= hw->queues); - - mutex_lock(&wdev->conf_mutex); - assign_bit(queue, &wvif->uapsd_mask, params->uapsd); - hif_set_edca_queue_params(wvif, queue, params); - if (wvif->vif->type == NL80211_IFTYPE_STATION && - old_uapsd != wvif->uapsd_mask) { - hif_set_uapsd_info(wvif, wvif->uapsd_mask); - wfx_update_pm(wvif); - } - mutex_unlock(&wdev->conf_mutex); - return 0; -} - -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = NULL; - - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - hif_rts_threshold(wvif, value); - return 0; -} - -/* WSM callbacks */ - -void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) -{ - /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 - * RSSI = RCPI / 2 - 110 - */ - int rcpi_rssi; - int cqm_evt; - - rcpi_rssi = raw_rcpi_rssi / 2 - 110; - if (rcpi_rssi <= wvif->vif->bss_conf.cqm_rssi_thold) - cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; - else - cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; - ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); -} - -static void wfx_beacon_loss_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(to_delayed_work(work), - struct wfx_vif, beacon_loss_work); - struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; - - ieee80211_beacon_loss(wvif->vif); - schedule_delayed_work(to_delayed_work(work), - msecs_to_jiffies(bss_conf->beacon_int)); -} - -void wfx_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - hif_wep_default_key_id(wvif, idx); -} - -void wfx_reset(struct wfx_vif *wvif) -{ - struct wfx_dev *wdev = wvif->wdev; - - wfx_tx_lock_flush(wdev); - hif_reset(wvif, false); - wfx_tx_policy_init(wvif); - if (wvif_count(wdev) <= 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - wfx_tx_unlock(wdev); - wvif->join_in_progress = false; - cancel_delayed_work_sync(&wvif->beacon_loss_work); - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); -} - -int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; - - sta_priv->vif_id = wvif->id; - - if (vif->type == NL80211_IFTYPE_STATION) - hif_set_mfp(wvif, sta->mfp, sta->mfp); - - // In station mode, the firmware interprets new link-id as a TDLS peer. - if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) - return 0; - sta_priv->link_id = ffz(wvif->link_id_map); - wvif->link_id_map |= BIT(sta_priv->link_id); - WARN_ON(!sta_priv->link_id); - WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX); - hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp); - - return 0; -} - -int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; - - // See note in wfx_sta_add() - if (!sta_priv->link_id) - return 0; - // FIXME add a mutex? - hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false); - wvif->link_id_map &= ~BIT(sta_priv->link_id); - return 0; -} - -static int wfx_upload_ap_templates(struct wfx_vif *wvif) -{ - struct sk_buff *skb; - - skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); - if (!skb) - return -ENOMEM; - hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, - API_RATE_INDEX_B_1MBPS); - dev_kfree_skb(skb); - - skb = ieee80211_proberesp_get(wvif->wdev->hw, wvif->vif); - if (!skb) - return -ENOMEM; - hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES, - API_RATE_INDEX_B_1MBPS); - dev_kfree_skb(skb); - return 0; -} - -static void wfx_set_mfp_ap(struct wfx_vif *wvif) -{ - struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); - const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); - const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, - skb->data + ieoffset, - skb->len - ieoffset); - const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); - const int pairwise_cipher_suite_size = 4 / sizeof(u16); - const int akm_suite_size = 4 / sizeof(u16); - - if (ptr) { - ptr += pairwise_cipher_suite_count_offset; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - ptr += 1 + pairwise_cipher_suite_size * *ptr; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - ptr += 1 + akm_suite_size * *ptr; - if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) - return; - hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); - } -} - -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct wfx_dev *wdev = wvif->wdev; - int ret; - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) - wfx_update_pm(wvif); - wvif = (struct wfx_vif *)vif->drv_priv; - wfx_upload_ap_templates(wvif); - ret = hif_start(wvif, &vif->bss_conf, wvif->channel); - if (ret > 0) - return -EIO; - wfx_set_mfp_ap(wvif); - return ret; -} - -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_reset(wvif); -} - -static void wfx_join(struct wfx_vif *wvif) -{ - int ret; - struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; - struct cfg80211_bss *bss = NULL; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - const u8 *ssidie = NULL; - int ssidlen = 0; - - wfx_tx_lock_flush(wvif->wdev); - - bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, - conf->bssid, NULL, 0, - IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); - if (!bss && !conf->ibss_joined) { - wfx_tx_unlock(wvif->wdev); - return; - } - - rcu_read_lock(); // protect ssidie - if (bss) - ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssidie) { - ssidlen = ssidie[1]; - if (ssidlen > IEEE80211_MAX_SSID_LEN) - ssidlen = IEEE80211_MAX_SSID_LEN; - memcpy(ssid, &ssidie[2], ssidlen); - } - rcu_read_unlock(); - - cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); - - wvif->join_in_progress = true; - ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); - if (ret) { - ieee80211_connection_loss(wvif->vif); - wfx_reset(wvif); - } else { - /* Due to beacon filtering it is possible that the - * AP's beacon is not known for the mac80211 stack. - * Disable filtering temporary to make sure the stack - * receives at least one - */ - wfx_filter_beacon(wvif, false); - } - wfx_tx_unlock(wvif->wdev); -} - -static void wfx_join_finalize(struct wfx_vif *wvif, - struct ieee80211_bss_conf *info) -{ - struct ieee80211_sta *sta = NULL; - int ampdu_density = 0; - bool greenfield = false; - - rcu_read_lock(); // protect sta - if (info->bssid && !info->ibss_joined) - sta = ieee80211_find_sta(wvif->vif, info->bssid); - if (sta && sta->ht_cap.ht_supported) - ampdu_density = sta->ht_cap.ampdu_density; - if (sta && sta->ht_cap.ht_supported && - !(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) - greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); - rcu_read_unlock(); - - wvif->join_in_progress = false; - hif_set_association_mode(wvif, ampdu_density, greenfield, - info->use_short_preamble); - hif_keep_alive_period(wvif, 0); - // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use - // the same value. - hif_set_bss_params(wvif, info->aid, 7); - hif_set_beacon_wakeup_period(wvif, 1, 1); - wfx_update_pm(wvif); -} - -int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_upload_ap_templates(wvif); - wfx_join(wvif); - return 0; -} - -void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wfx_reset(wvif); -} - -static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) -{ - // Driver has Content After DTIM Beacon in queue. Driver is waiting for - // a signal from the firmware. Since we are going to stop to send - // beacons, this signal will never happens. See also - // wfx_suspend_resume_mc() - if (!enable && wfx_tx_queues_has_cab(wvif)) { - wvif->after_dtim_tx_allowed = true; - wfx_bh_request_tx(wvif->wdev); - } - hif_beacon_transmit(wvif, enable); -} - -void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - int i; - - mutex_lock(&wdev->conf_mutex); - - if (changed & BSS_CHANGED_BASIC_RATES || - changed & BSS_CHANGED_BEACON_INT || - changed & BSS_CHANGED_BSSID) { - if (vif->type == NL80211_IFTYPE_STATION) - wfx_join(wvif); - } - - if (changed & BSS_CHANGED_ASSOC) { - if (info->assoc || info->ibss_joined) - wfx_join_finalize(wvif, info); - else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) - wfx_reset(wvif); - else - dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n", - __func__); - } - - if (changed & BSS_CHANGED_BEACON_INFO) { - if (vif->type != NL80211_IFTYPE_STATION) - dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n", - __func__); - hif_set_beacon_wakeup_period(wvif, info->dtim_period, - info->dtim_period); - // We temporary forwarded beacon for join process. It is now no - // more necessary. - wfx_filter_beacon(wvif, true); - } - - if (changed & BSS_CHANGED_ARP_FILTER) { - for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { - __be32 *arp_addr = &info->arp_addr_list[i]; - - if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) - arp_addr = NULL; - if (i >= info->arp_addr_cnt) - arp_addr = NULL; - hif_set_arp_ipv4_filter(wvif, i, arp_addr); - } - } - - if (changed & BSS_CHANGED_AP_PROBE_RESP || - changed & BSS_CHANGED_BEACON) - wfx_upload_ap_templates(wvif); - - if (changed & BSS_CHANGED_BEACON_ENABLED) - wfx_enable_beacon(wvif, info->enable_beacon); - - if (changed & BSS_CHANGED_KEEP_ALIVE) - hif_keep_alive_period(wvif, info->max_idle_period * - USEC_PER_TU / USEC_PER_MSEC); - - if (changed & BSS_CHANGED_ERP_CTS_PROT) - hif_erp_use_protection(wvif, info->use_cts_prot); - - if (changed & BSS_CHANGED_ERP_SLOT) - hif_slot_time(wvif, info->use_short_slot ? 9 : 20); - - if (changed & BSS_CHANGED_CQM) - hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, - info->cqm_rssi_hyst); - - if (changed & BSS_CHANGED_TXPOWER) - hif_set_output_power(wvif, info->txpower); - - if (changed & BSS_CHANGED_PS) - wfx_update_pm(wvif); - - mutex_unlock(&wdev->conf_mutex); -} - -static int wfx_update_tim(struct wfx_vif *wvif) -{ - struct sk_buff *skb; - u16 tim_offset, tim_length; - u8 *tim_ptr; - - skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, - &tim_offset, &tim_length); - if (!skb) - return -ENOENT; - tim_ptr = skb->data + tim_offset; - - if (tim_offset && tim_length >= 6) { - /* Ignore DTIM count from mac80211: - * firmware handles DTIM internally. - */ - tim_ptr[2] = 0; - - /* Set/reset aid0 bit */ - if (wfx_tx_queues_has_cab(wvif)) - tim_ptr[4] |= 1; - else - tim_ptr[4] &= ~1; - } - - hif_update_ie_beacon(wvif, tim_ptr, tim_length); - dev_kfree_skb(skb); - - return 0; -} - -static void wfx_update_tim_work(struct work_struct *work) -{ - struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work); - - wfx_update_tim(wvif); -} - -int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv; - struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id); - - if (!wvif) { - dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); - return -EIO; - } - schedule_work(&wvif->update_tim_work); - return 0; -} - -void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) -{ - if (notify_cmd != STA_NOTIFY_AWAKE) - return; - WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); - WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); - wvif->after_dtim_tx_allowed = true; - wfx_bh_request_tx(wvif->wdev); -} - -int wfx_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) -{ - // Aggregation is implemented fully in firmware - switch (params->action) { - case IEEE80211_AMPDU_RX_START: - case IEEE80211_AMPDU_RX_STOP: - // Just acknowledge it to enable frame re-ordering - return 0; - default: - // Leave the firmware doing its business for tx aggregation - return -ENOTSUPP; - } -} - -int wfx_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf) -{ - return 0; -} - -void wfx_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf) -{ -} - -void wfx_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf, - u32 changed) -{ -} - -int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct ieee80211_channel *ch = conf->def.chan; - - WARN(wvif->channel, "channel overwrite"); - wvif->channel = ch; - - return 0; -} - -void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf) -{ - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - struct ieee80211_channel *ch = conf->def.chan; - - WARN(wvif->channel != ch, "channel mismatch"); - wvif->channel = NULL; -} - -int wfx_config(struct ieee80211_hw *hw, u32 changed) -{ - return 0; -} - -int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - int i, ret = 0; - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | - IEEE80211_VIF_SUPPORTS_UAPSD | - IEEE80211_VIF_SUPPORTS_CQM_RSSI; - - mutex_lock(&wdev->conf_mutex); - - switch (vif->type) { - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_AP: - break; - default: - mutex_unlock(&wdev->conf_mutex); - return -EOPNOTSUPP; - } - - // FIXME: prefer use of container_of() to get vif - wvif->vif = vif; - wvif->wdev = wdev; - - wvif->link_id_map = 1; // link-id 0 is reserved for multicast - INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); - INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); - - init_completion(&wvif->set_pm_mode_complete); - complete(&wvif->set_pm_mode_complete); - INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); - - mutex_init(&wvif->scan_lock); - init_completion(&wvif->scan_complete); - INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); - - wfx_tx_queues_init(wvif); - wfx_tx_policy_init(wvif); - - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - if (!wdev->vif[i]) { - wdev->vif[i] = vif; - wvif->id = i; - break; - } - } - WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported"); - - hif_set_macaddr(wvif, vif->addr); - - mutex_unlock(&wdev->conf_mutex); - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - // Combo mode does not support Block Acks. We can re-enable them - if (wvif_count(wdev) == 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - else - hif_set_block_ack_policy(wvif, 0x00, 0x00); - } - return ret; -} - -void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) -{ - struct wfx_dev *wdev = hw->priv; - struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; - - wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); - wfx_tx_queues_check_empty(wvif); - - mutex_lock(&wdev->conf_mutex); - WARN(wvif->link_id_map != 1, "corrupted state"); - - hif_reset(wvif, false); - hif_set_macaddr(wvif, NULL); - wfx_tx_policy_init(wvif); - - cancel_delayed_work_sync(&wvif->beacon_loss_work); - wdev->vif[wvif->id] = NULL; - wvif->vif = NULL; - - mutex_unlock(&wdev->conf_mutex); - - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - // Combo mode does not support Block Acks. We can re-enable them - if (wvif_count(wdev) == 1) - hif_set_block_ack_policy(wvif, 0xFF, 0xFF); - else - hif_set_block_ack_policy(wvif, 0x00, 0x00); - } -} - -int wfx_start(struct ieee80211_hw *hw) -{ - return 0; -} - -void wfx_stop(struct ieee80211_hw *hw) -{ - struct wfx_dev *wdev = hw->priv; - - WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending)); -} diff --git a/drivers/staging/wfx/sta.h b/drivers/staging/wfx/sta.h deleted file mode 100644 index d7b5df5ea4e6..000000000000 --- a/drivers/staging/wfx/sta.h +++ /dev/null @@ -1,73 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Implementation of mac80211 API. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - */ -#ifndef WFX_STA_H -#define WFX_STA_H - -#include - -struct wfx_dev; -struct wfx_vif; - -struct wfx_sta_priv { - int link_id; - int vif_id; -}; - -// mac80211 interface -int wfx_start(struct ieee80211_hw *hw); -void wfx_stop(struct ieee80211_hw *hw); -int wfx_config(struct ieee80211_hw *hw, u32 changed); -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); -void wfx_set_default_unicast_key(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, int idx); -void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, - unsigned int *total_flags, u64 unused); - -int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u16 queue, const struct ieee80211_tx_queue_params *params); -void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, u32 changed); -int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta); -void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - enum sta_notify_cmd cmd, struct ieee80211_sta *sta); -int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); -int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params); -int wfx_add_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf); -void wfx_remove_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf); -void wfx_change_chanctx(struct ieee80211_hw *hw, - struct ieee80211_chanctx_conf *conf, u32 changed); -int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf); -void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_chanctx_conf *conf); - -// WSM Callbacks -void wfx_cooling_timeout_work(struct work_struct *work); -void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); -void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); -void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); -int wfx_update_pm(struct wfx_vif *wvif); - -// Other Helpers -void wfx_reset(struct wfx_vif *wvif); -u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates); - -#endif /* WFX_STA_H */ diff --git a/drivers/staging/wfx/traces.h b/drivers/staging/wfx/traces.h deleted file mode 100644 index e34c7a538c65..000000000000 --- a/drivers/staging/wfx/traces.h +++ /dev/null @@ -1,501 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Tracepoints definitions. - * - * Copyright (c) 2018-2020, Silicon Laboratories, Inc. - */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM wfx - -#if !defined(_WFX_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _WFX_TRACE_H - -#include -#include - -#include "bus.h" -#include "hif_api_cmd.h" -#include "hif_api_mib.h" - -/* The hell below need some explanations. For each symbolic number, we need to - * define it with TRACE_DEFINE_ENUM() and in a list for __print_symbolic. - * - * 1. Define a new macro that call TRACE_DEFINE_ENUM(): - * - * #define xxx_name(sym) TRACE_DEFINE_ENUM(sym); - * - * 2. Define list of all symbols: - * - * #define list_names \ - * ... \ - * xxx_name(XXX) \ - * ... - * - * 3. Instantiate that list_names: - * - * list_names - * - * 4. Redefine xxx_name() as an entry of array for __print_symbolic() - * - * #undef xxx_name - * #define xxx_name(msg) { msg, #msg }, - * - * 5. list_name can now nearly be used with __print_symbolic() but, - * __print_symbolic() dislike last comma of list. So we define a new list - * with a dummy element: - * - * #define list_for_print_symbolic list_names { -1, NULL } - */ - -#define _hif_msg_list \ - hif_cnf_name(ADD_KEY) \ - hif_cnf_name(BEACON_TRANSMIT) \ - hif_cnf_name(EDCA_QUEUE_PARAMS) \ - hif_cnf_name(JOIN) \ - hif_cnf_name(MAP_LINK) \ - hif_cnf_name(READ_MIB) \ - hif_cnf_name(REMOVE_KEY) \ - hif_cnf_name(RESET) \ - hif_cnf_name(SET_BSS_PARAMS) \ - hif_cnf_name(SET_PM_MODE) \ - hif_cnf_name(START) \ - hif_cnf_name(START_SCAN) \ - hif_cnf_name(STOP_SCAN) \ - hif_cnf_name(TX) \ - hif_cnf_name(MULTI_TRANSMIT) \ - hif_cnf_name(UPDATE_IE) \ - hif_cnf_name(WRITE_MIB) \ - hif_cnf_name(CONFIGURATION) \ - hif_cnf_name(CONTROL_GPIO) \ - hif_cnf_name(PREVENT_ROLLBACK) \ - hif_cnf_name(SET_SL_MAC_KEY) \ - hif_cnf_name(SL_CONFIGURE) \ - hif_cnf_name(SL_EXCHANGE_PUB_KEYS) \ - hif_cnf_name(SHUT_DOWN) \ - hif_ind_name(EVENT) \ - hif_ind_name(JOIN_COMPLETE) \ - hif_ind_name(RX) \ - hif_ind_name(SCAN_CMPL) \ - hif_ind_name(SET_PM_MODE_CMPL) \ - hif_ind_name(SUSPEND_RESUME_TX) \ - hif_ind_name(SL_EXCHANGE_PUB_KEYS) \ - hif_ind_name(ERROR) \ - hif_ind_name(EXCEPTION) \ - hif_ind_name(GENERIC) \ - hif_ind_name(WAKEUP) \ - hif_ind_name(STARTUP) - -#define hif_msg_list_enum _hif_msg_list - -#undef hif_cnf_name -#undef hif_ind_name -#define hif_cnf_name(msg) TRACE_DEFINE_ENUM(HIF_CNF_ID_##msg); -#define hif_ind_name(msg) TRACE_DEFINE_ENUM(HIF_IND_ID_##msg); -hif_msg_list_enum -#undef hif_cnf_name -#undef hif_ind_name -#define hif_cnf_name(msg) { HIF_CNF_ID_##msg, #msg }, -#define hif_ind_name(msg) { HIF_IND_ID_##msg, #msg }, -#define hif_msg_list hif_msg_list_enum { -1, NULL } - -#define _hif_mib_list \ - hif_mib_name(ARP_IP_ADDRESSES_TABLE) \ - hif_mib_name(ARP_KEEP_ALIVE_PERIOD) \ - hif_mib_name(BEACON_FILTER_ENABLE) \ - hif_mib_name(BEACON_FILTER_TABLE) \ - hif_mib_name(BEACON_STATS) \ - hif_mib_name(BEACON_WAKEUP_PERIOD) \ - hif_mib_name(BLOCK_ACK_POLICY) \ - hif_mib_name(CCA_CONFIG) \ - hif_mib_name(CONFIG_DATA_FILTER) \ - hif_mib_name(COUNTERS_TABLE) \ - hif_mib_name(CURRENT_TX_POWER_LEVEL) \ - hif_mib_name(DOT11_MAC_ADDRESS) \ - hif_mib_name(DOT11_MAX_RECEIVE_LIFETIME) \ - hif_mib_name(DOT11_MAX_TRANSMIT_MSDU_LIFETIME) \ - hif_mib_name(DOT11_RTS_THRESHOLD) \ - hif_mib_name(DOT11_WEP_DEFAULT_KEY_ID) \ - hif_mib_name(ETHERTYPE_DATAFRAME_CONDITION) \ - hif_mib_name(EXTENDED_COUNTERS_TABLE) \ - hif_mib_name(GL_BLOCK_ACK_INFO) \ - hif_mib_name(GL_OPERATIONAL_POWER_MODE) \ - hif_mib_name(GL_SET_MULTI_MSG) \ - hif_mib_name(GRP_SEQ_COUNTER) \ - hif_mib_name(INACTIVITY_TIMER) \ - hif_mib_name(INTERFACE_PROTECTION) \ - hif_mib_name(IPV4_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(IPV6_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(KEEP_ALIVE_PERIOD) \ - hif_mib_name(MAC_ADDR_DATAFRAME_CONDITION) \ - hif_mib_name(MAGIC_DATAFRAME_CONDITION) \ - hif_mib_name(MAX_TX_POWER_LEVEL) \ - hif_mib_name(NON_ERP_PROTECTION) \ - hif_mib_name(NS_IP_ADDRESSES_TABLE) \ - hif_mib_name(OVERRIDE_INTERNAL_TX_RATE) \ - hif_mib_name(PORT_DATAFRAME_CONDITION) \ - hif_mib_name(PROTECTED_MGMT_POLICY) \ - hif_mib_name(RCPI_RSSI_THRESHOLD) \ - hif_mib_name(RX_FILTER) \ - hif_mib_name(SET_ASSOCIATION_MODE) \ - hif_mib_name(SET_DATA_FILTERING) \ - hif_mib_name(SET_HT_PROTECTION) \ - hif_mib_name(SET_TX_RATE_RETRY_POLICY) \ - hif_mib_name(SET_UAPSD_INFORMATION) \ - hif_mib_name(SLOT_TIME) \ - hif_mib_name(STATISTICS_TABLE) \ - hif_mib_name(TEMPLATE_FRAME) \ - hif_mib_name(TSF_COUNTER) \ - hif_mib_name(UC_MC_BC_DATAFRAME_CONDITION) - -#define hif_mib_list_enum _hif_mib_list - -#undef hif_mib_name -#define hif_mib_name(mib) TRACE_DEFINE_ENUM(HIF_MIB_ID_##mib); -hif_mib_list_enum -#undef hif_mib_name -#define hif_mib_name(mib) { HIF_MIB_ID_##mib, #mib }, -#define hif_mib_list hif_mib_list_enum { -1, NULL } - -DECLARE_EVENT_CLASS(hif_data, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv), - TP_STRUCT__entry( - __field(int, tx_fill_level) - __field(int, msg_id) - __field(const char *, msg_type) - __field(int, msg_len) - __field(int, buf_len) - __field(int, if_id) - __field(int, mib) - __array(u8, buf, 128) - ), - TP_fast_assign( - int header_len; - - __entry->tx_fill_level = tx_fill_level; - __entry->msg_len = le16_to_cpu(hif->len); - __entry->msg_id = hif->id; - __entry->if_id = hif->interface; - if (is_recv) - __entry->msg_type = __entry->msg_id & 0x80 ? "IND" : "CNF"; - else - __entry->msg_type = "REQ"; - if (!is_recv && - (__entry->msg_id == HIF_REQ_ID_READ_MIB || - __entry->msg_id == HIF_REQ_ID_WRITE_MIB)) { - __entry->mib = le16_to_cpup((__le16 *)hif->body); - header_len = 4; - } else { - __entry->mib = -1; - header_len = 0; - } - __entry->buf_len = min_t(int, __entry->msg_len, - sizeof(__entry->buf)) - - sizeof(struct hif_msg) - header_len; - memcpy(__entry->buf, hif->body + header_len, __entry->buf_len); - ), - TP_printk("%d:%d:%s_%s%s%s: %s%s (%d bytes)", - __entry->tx_fill_level, - __entry->if_id, - __entry->msg_type, - __print_symbolic(__entry->msg_id, hif_msg_list), - __entry->mib != -1 ? "/" : "", - __entry->mib != -1 ? __print_symbolic(__entry->mib, hif_mib_list) : "", - __print_hex(__entry->buf, __entry->buf_len), - __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", - __entry->msg_len - ) -); -DEFINE_EVENT(hif_data, hif_send, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv)); -#define _trace_hif_send(hif, tx_fill_level)\ - trace_hif_send(hif, tx_fill_level, false) -DEFINE_EVENT(hif_data, hif_recv, - TP_PROTO(const struct hif_msg *hif, int tx_fill_level, bool is_recv), - TP_ARGS(hif, tx_fill_level, is_recv)); -#define _trace_hif_recv(hif, tx_fill_level)\ - trace_hif_recv(hif, tx_fill_level, true) - -#define wfx_reg_list_enum \ - wfx_reg_name(WFX_REG_CONFIG, "CONFIG") \ - wfx_reg_name(WFX_REG_CONTROL, "CONTROL") \ - wfx_reg_name(WFX_REG_IN_OUT_QUEUE, "QUEUE") \ - wfx_reg_name(WFX_REG_AHB_DPORT, "AHB") \ - wfx_reg_name(WFX_REG_BASE_ADDR, "BASE_ADDR") \ - wfx_reg_name(WFX_REG_SRAM_DPORT, "SRAM") \ - wfx_reg_name(WFX_REG_SET_GEN_R_W, "SET_GEN_R_W") \ - wfx_reg_name(WFX_REG_FRAME_OUT, "FRAME_OUT") - -#undef wfx_reg_name -#define wfx_reg_name(sym, name) TRACE_DEFINE_ENUM(sym); -wfx_reg_list_enum -#undef wfx_reg_name -#define wfx_reg_name(sym, name) { sym, name }, -#define wfx_reg_list wfx_reg_list_enum { -1, NULL } - -DECLARE_EVENT_CLASS(io_data, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len), - TP_STRUCT__entry( - __field(int, reg) - __field(int, addr) - __field(int, msg_len) - __field(int, buf_len) - __array(u8, buf, 32) - __array(u8, addr_str, 10) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->addr = addr; - __entry->msg_len = len; - __entry->buf_len = min_t(int, sizeof(__entry->buf), - __entry->msg_len); - memcpy(__entry->buf, io_buf, __entry->buf_len); - if (addr >= 0) - snprintf(__entry->addr_str, 10, "/%08x", addr); - else - __entry->addr_str[0] = 0; - ), - TP_printk("%s%s: %s%s (%d bytes)", - __print_symbolic(__entry->reg, wfx_reg_list), - __entry->addr_str, - __print_hex(__entry->buf, __entry->buf_len), - __entry->msg_len > sizeof(__entry->buf) ? " ..." : "", - __entry->msg_len - ) -); -DEFINE_EVENT(io_data, io_write, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len)); -#define _trace_io_ind_write(reg, addr, io_buf, len)\ - trace_io_write(reg, addr, io_buf, len) -#define _trace_io_write(reg, io_buf, len) trace_io_write(reg, -1, io_buf, len) -DEFINE_EVENT(io_data, io_read, - TP_PROTO(int reg, int addr, const void *io_buf, size_t len), - TP_ARGS(reg, addr, io_buf, len)); -#define _trace_io_ind_read(reg, addr, io_buf, len)\ - trace_io_read(reg, addr, io_buf, len) -#define _trace_io_read(reg, io_buf, len) trace_io_read(reg, -1, io_buf, len) - -DECLARE_EVENT_CLASS(io_data32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val), - TP_STRUCT__entry( - __field(int, reg) - __field(int, addr) - __field(int, val) - __array(u8, addr_str, 10) - ), - TP_fast_assign( - __entry->reg = reg; - __entry->addr = addr; - __entry->val = val; - if (addr >= 0) - snprintf(__entry->addr_str, 10, "/%08x", addr); - else - __entry->addr_str[0] = 0; - ), - TP_printk("%s%s: %08x", - __print_symbolic(__entry->reg, wfx_reg_list), - __entry->addr_str, - __entry->val - ) -); -DEFINE_EVENT(io_data32, io_write32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val)); -#define _trace_io_ind_write32(reg, addr, val) trace_io_write32(reg, addr, val) -#define _trace_io_write32(reg, val) trace_io_write32(reg, -1, val) -DEFINE_EVENT(io_data32, io_read32, - TP_PROTO(int reg, int addr, u32 val), - TP_ARGS(reg, addr, val)); -#define _trace_io_ind_read32(reg, addr, val) trace_io_read32(reg, addr, val) -#define _trace_io_read32(reg, val) trace_io_read32(reg, -1, val) - -DECLARE_EVENT_CLASS(piggyback, - TP_PROTO(u32 val, bool ignored), - TP_ARGS(val, ignored), - TP_STRUCT__entry( - __field(int, val) - __field(bool, ignored) - ), - TP_fast_assign( - __entry->val = val; - __entry->ignored = ignored; - ), - TP_printk("CONTROL: %08x%s", - __entry->val, - __entry->ignored ? " (ignored)" : "" - ) -); -DEFINE_EVENT(piggyback, piggyback, - TP_PROTO(u32 val, bool ignored), - TP_ARGS(val, ignored)); -#define _trace_piggyback(val, ignored) trace_piggyback(val, ignored) - -TRACE_EVENT(bh_stats, - TP_PROTO(int ind, int req, int cnf, int busy, bool release), - TP_ARGS(ind, req, cnf, busy, release), - TP_STRUCT__entry( - __field(int, ind) - __field(int, req) - __field(int, cnf) - __field(int, busy) - __field(bool, release) - ), - TP_fast_assign( - __entry->ind = ind; - __entry->req = req; - __entry->cnf = cnf; - __entry->busy = busy; - __entry->release = release; - ), - TP_printk("IND/REQ/CNF:%3d/%3d/%3d, REQ in progress:%3d, WUP: %s", - __entry->ind, - __entry->req, - __entry->cnf, - __entry->busy, - __entry->release ? "release" : "keep" - ) -); -#define _trace_bh_stats(ind, req, cnf, busy, release)\ - trace_bh_stats(ind, req, cnf, busy, release) - -TRACE_EVENT(tx_stats, - TP_PROTO(const struct hif_cnf_tx *tx_cnf, const struct sk_buff *skb, - int delay), - TP_ARGS(tx_cnf, skb, delay), - TP_STRUCT__entry( - __field(int, pkt_id) - __field(int, delay_media) - __field(int, delay_queue) - __field(int, delay_fw) - __field(int, ack_failures) - __field(int, flags) - __array(int, rate, 4) - __array(int, tx_count, 4) - ), - TP_fast_assign( - // Keep sync with wfx_rates definition in main.c - static const int hw_rate[] = { 0, 1, 2, 3, 6, 7, 8, 9, - 10, 11, 12, 13 }; - const struct ieee80211_tx_info *tx_info = - (const struct ieee80211_tx_info *)skb->cb; - const struct ieee80211_tx_rate *rates = tx_info->driver_rates; - int i; - - __entry->pkt_id = tx_cnf->packet_id; - __entry->delay_media = le32_to_cpu(tx_cnf->media_delay); - __entry->delay_queue = le32_to_cpu(tx_cnf->tx_queue_delay); - __entry->delay_fw = delay; - __entry->ack_failures = tx_cnf->ack_failures; - if (!tx_cnf->status || __entry->ack_failures) - __entry->ack_failures += 1; - - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - if (rates[0].flags & IEEE80211_TX_RC_MCS) - __entry->rate[i] = rates[i].idx; - else - __entry->rate[i] = hw_rate[rates[i].idx]; - __entry->tx_count[i] = rates[i].count; - } - __entry->flags = 0; - if (rates[0].flags & IEEE80211_TX_RC_MCS) - __entry->flags |= 0x01; - if (rates[0].flags & IEEE80211_TX_RC_SHORT_GI) - __entry->flags |= 0x02; - if (rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD) - __entry->flags |= 0x04; - if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) - __entry->flags |= 0x08; - if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) - __entry->flags |= 0x10; - if (tx_cnf->status) - __entry->flags |= 0x20; - if (tx_cnf->status == HIF_STATUS_TX_FAIL_REQUEUE) - __entry->flags |= 0x40; - ), - TP_printk("packet ID: %08x, rate policy: %s %d|%d %d|%d %d|%d %d|%d -> %d attempt, Delays media/queue/total: %4dus/%4dus/%4dus", - __entry->pkt_id, - __print_flags(__entry->flags, NULL, - { 0x01, "M" }, { 0x02, "S" }, { 0x04, "G" }, - { 0x08, "R" }, { 0x10, "D" }, { 0x20, "F" }, - { 0x40, "Q" }), - __entry->rate[0], - __entry->tx_count[0], - __entry->rate[1], - __entry->tx_count[1], - __entry->rate[2], - __entry->tx_count[2], - __entry->rate[3], - __entry->tx_count[3], - __entry->ack_failures, - __entry->delay_media, - __entry->delay_queue, - __entry->delay_fw - ) -); -#define _trace_tx_stats(tx_cnf, skb, delay) trace_tx_stats(tx_cnf, skb, delay) - -TRACE_EVENT(queues_stats, - TP_PROTO(struct wfx_dev *wdev, const struct wfx_queue *elected_queue), - TP_ARGS(wdev, elected_queue), - TP_STRUCT__entry( - __field(int, vif_id) - __field(int, queue_id) - __array(int, hw, IEEE80211_NUM_ACS * 2) - __array(int, drv, IEEE80211_NUM_ACS * 2) - __array(int, cab, IEEE80211_NUM_ACS * 2) - ), - TP_fast_assign( - const struct wfx_queue *queue; - struct wfx_vif *wvif; - int i, j; - - for (j = 0; j < IEEE80211_NUM_ACS * 2; j++) { - __entry->hw[j] = -1; - __entry->drv[j] = -1; - __entry->cab[j] = -1; - } - __entry->vif_id = -1; - __entry->queue_id = -1; - wvif = NULL; - while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - j = wvif->id * IEEE80211_NUM_ACS + i; - WARN_ON(j >= IEEE80211_NUM_ACS * 2); - queue = &wvif->tx_queue[i]; - __entry->hw[j] = atomic_read(&queue->pending_frames); - __entry->drv[j] = skb_queue_len(&queue->normal); - __entry->cab[j] = skb_queue_len(&queue->cab); - if (queue == elected_queue) { - __entry->vif_id = wvif->id; - __entry->queue_id = i; - } - } - } - ), - TP_printk("got skb from %d/%d, pend. hw/norm/cab: [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ] [ %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d ]", - __entry->vif_id, __entry->queue_id, - __entry->hw[0], __entry->drv[0], __entry->cab[0], - __entry->hw[1], __entry->drv[1], __entry->cab[1], - __entry->hw[2], __entry->drv[2], __entry->cab[2], - __entry->hw[3], __entry->drv[3], __entry->cab[3], - __entry->hw[4], __entry->drv[4], __entry->cab[4], - __entry->hw[5], __entry->drv[5], __entry->cab[5], - __entry->hw[6], __entry->drv[6], __entry->cab[6], - __entry->hw[7], __entry->drv[7], __entry->cab[7] - ) -); - -#endif - -/* This part must be outside protection */ -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE traces - -#include diff --git a/drivers/staging/wfx/wfx.h b/drivers/staging/wfx/wfx.h deleted file mode 100644 index 94898680ccde..000000000000 --- a/drivers/staging/wfx/wfx.h +++ /dev/null @@ -1,166 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Common private data for Silicon Labs WFx chips. - * - * Copyright (c) 2017-2020, Silicon Laboratories, Inc. - * Copyright (c) 2010, ST-Ericsson - * Copyright (c) 2006, Michael Wu - * Copyright 2004-2006 Jean-Baptiste Note , et al. - */ -#ifndef WFX_H -#define WFX_H - -#include -#include -#include -#include -#include - -#include "bh.h" -#include "data_tx.h" -#include "main.h" -#include "queue.h" -#include "hif_tx.h" - -#define USEC_PER_TXOP 32 // see struct ieee80211_tx_queue_params -#define USEC_PER_TU 1024 - -struct hwbus_ops; - -struct wfx_dev { - struct wfx_platform_data pdata; - struct device *dev; - struct ieee80211_hw *hw; - struct ieee80211_vif *vif[2]; - struct mac_address addresses[2]; - const struct hwbus_ops *hwbus_ops; - void *hwbus_priv; - - u8 keyset; - struct completion firmware_ready; - struct hif_ind_startup hw_caps; - struct wfx_hif hif; - struct delayed_work cooling_timeout_work; - bool poll_irq; - bool chip_frozen; - struct mutex conf_mutex; - - struct wfx_hif_cmd hif_cmd; - struct sk_buff_head tx_pending; - wait_queue_head_t tx_dequeue; - atomic_t tx_lock; - - atomic_t packet_id; - u32 key_map; - - struct hif_rx_stats rx_stats; - struct mutex rx_stats_lock; - struct hif_tx_power_loop_info tx_power_loop_info; - struct mutex tx_power_loop_info_lock; - int force_ps_timeout; -}; - -struct wfx_vif { - struct wfx_dev *wdev; - struct ieee80211_vif *vif; - struct ieee80211_channel *channel; - int id; - - u32 link_id_map; - - bool after_dtim_tx_allowed; - bool join_in_progress; - - struct delayed_work beacon_loss_work; - - struct wfx_queue tx_queue[4]; - struct tx_policy_cache tx_policy_cache; - struct work_struct tx_policy_upload_work; - - struct work_struct update_tim_work; - - unsigned long uapsd_mask; - - /* avoid some operations in parallel with scan */ - struct mutex scan_lock; - struct work_struct scan_work; - struct completion scan_complete; - bool scan_abort; - struct ieee80211_scan_request *scan_req; - - struct completion set_pm_mode_complete; -}; - -static inline struct wfx_vif *wdev_to_wvif(struct wfx_dev *wdev, int vif_id) -{ - if (vif_id >= ARRAY_SIZE(wdev->vif)) { - dev_dbg(wdev->dev, "requesting non-existent vif: %d\n", vif_id); - return NULL; - } - vif_id = array_index_nospec(vif_id, ARRAY_SIZE(wdev->vif)); - if (!wdev->vif[vif_id]) { - dev_dbg(wdev->dev, "requesting non-allocated vif: %d\n", - vif_id); - return NULL; - } - return (struct wfx_vif *) wdev->vif[vif_id]->drv_priv; -} - -static inline struct wfx_vif *wvif_iterate(struct wfx_dev *wdev, - struct wfx_vif *cur) -{ - int i; - int mark = 0; - struct wfx_vif *tmp; - - if (!cur) - mark = 1; - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - tmp = wdev_to_wvif(wdev, i); - if (mark && tmp) - return tmp; - if (tmp == cur) - mark = 1; - } - return NULL; -} - -static inline int wvif_count(struct wfx_dev *wdev) -{ - int i; - int ret = 0; - struct wfx_vif *wvif; - - for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { - wvif = wdev_to_wvif(wdev, i); - if (wvif) - ret++; - } - return ret; -} - -static inline void memreverse(u8 *src, u8 length) -{ - u8 *lo = src; - u8 *hi = src + length - 1; - u8 swap; - - while (lo < hi) { - swap = *lo; - *lo++ = *hi; - *hi-- = swap; - } -} - -static inline int memzcmp(void *src, unsigned int size) -{ - u8 *buf = src; - - if (!size) - return 0; - if (*buf) - return 1; - return memcmp(buf, buf + 1, size - 1); -} - -#endif /* WFX_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:51:54 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:51:54 +0100 Subject: [PATCH v3 11/24] wfx: add bh.c/bh.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-12-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/bh.c | 333 +++++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/bh.h | 33 +++ 2 files changed, 366 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/bh.c create mode 100644 drivers/net/wireless/silabs/wfx/bh.h diff --git a/drivers/net/wireless/silabs/wfx/bh.c b/drivers/net/wireless/silabs/wfx/bh.c new file mode 100644 index 000000000000..ed53d0b45592 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bh.c @@ -0,0 +1,333 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Interrupt bottom half (BH). + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "bh.h" +#include "wfx.h" +#include "hwio.h" +#include "traces.h" +#include "hif_rx.h" +#include "hif_api_cmd.h" + +static void device_wakeup(struct wfx_dev *wdev) +{ + int max_retry = 3; + + if (!wdev->pdata.gpio_wakeup) + return; + if (gpiod_get_value_cansleep(wdev->pdata.gpio_wakeup) > 0) + return; + + if (wfx_api_older_than(wdev, 1, 4)) { + gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); + if (!completion_done(&wdev->hif.ctrl_ready)) + usleep_range(2000, 2500); + return; + } + for (;;) { + gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 1); + // completion.h does not provide any function to wait + // completion without consume it (a kind of + // wait_for_completion_done_timeout()). So we have to emulate + // it. + if (wait_for_completion_timeout(&wdev->hif.ctrl_ready, + msecs_to_jiffies(2))) { + complete(&wdev->hif.ctrl_ready); + return; + } else if (max_retry-- > 0) { + // Older firmwares have a race in sleep/wake-up process. + // Redo the process is sufficient to unfreeze the + // chip. + dev_err(wdev->dev, "timeout while wake up chip\n"); + gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); + usleep_range(2000, 2500); + } else { + dev_err(wdev->dev, "max wake-up retries reached\n"); + return; + } + } +} + +static void device_release(struct wfx_dev *wdev) +{ + if (!wdev->pdata.gpio_wakeup) + return; + + gpiod_set_value_cansleep(wdev->pdata.gpio_wakeup, 0); +} + +static int rx_helper(struct wfx_dev *wdev, size_t read_len, int *is_cnf) +{ + struct sk_buff *skb; + struct hif_msg *hif; + size_t alloc_len; + size_t computed_len; + int release_count; + int piggyback = 0; + + WARN(read_len > round_down(0xFFF, 2) * sizeof(u16), + "%s: request exceed WFx capability", __func__); + + // Add 2 to take into account piggyback size + alloc_len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, read_len + 2); + skb = dev_alloc_skb(alloc_len); + if (!skb) + return -ENOMEM; + + if (wfx_data_read(wdev, skb->data, alloc_len)) + goto err; + + piggyback = le16_to_cpup((__le16 *)(skb->data + alloc_len - 2)); + _trace_piggyback(piggyback, false); + + hif = (struct hif_msg *)skb->data; + WARN(hif->encrypted & 0x3, "encryption is unsupported"); + if (WARN(read_len < sizeof(struct hif_msg), "corrupted read")) + goto err; + computed_len = le16_to_cpu(hif->len); + computed_len = round_up(computed_len, 2); + if (computed_len != read_len) { + dev_err(wdev->dev, "inconsistent message length: %zu != %zu\n", + computed_len, read_len); + print_hex_dump(KERN_INFO, "hif: ", DUMP_PREFIX_OFFSET, 16, 1, + hif, read_len, true); + goto err; + } + + if (!(hif->id & HIF_ID_IS_INDICATION)) { + (*is_cnf)++; + if (hif->id == HIF_CNF_ID_MULTI_TRANSMIT) + release_count = ((struct hif_cnf_multi_transmit *)hif->body)->num_tx_confs; + else + release_count = 1; + WARN(wdev->hif.tx_buffers_used < release_count, "corrupted buffer counter"); + wdev->hif.tx_buffers_used -= release_count; + } + _trace_hif_recv(hif, wdev->hif.tx_buffers_used); + + if (hif->id != HIF_IND_ID_EXCEPTION && hif->id != HIF_IND_ID_ERROR) { + if (hif->seqnum != wdev->hif.rx_seqnum) + dev_warn(wdev->dev, "wrong message sequence: %d != %d\n", + hif->seqnum, wdev->hif.rx_seqnum); + wdev->hif.rx_seqnum = (hif->seqnum + 1) % (HIF_COUNTER_MAX + 1); + } + + skb_put(skb, le16_to_cpu(hif->len)); + // wfx_handle_rx takes care on SKB livetime + wfx_handle_rx(wdev, skb); + if (!wdev->hif.tx_buffers_used) + wake_up(&wdev->hif.tx_buffers_empty); + + return piggyback; + +err: + if (skb) + dev_kfree_skb(skb); + return -EIO; +} + +static int bh_work_rx(struct wfx_dev *wdev, int max_msg, int *num_cnf) +{ + size_t len; + int i; + int ctrl_reg, piggyback; + + piggyback = 0; + for (i = 0; i < max_msg; i++) { + if (piggyback & CTRL_NEXT_LEN_MASK) + ctrl_reg = piggyback; + else if (try_wait_for_completion(&wdev->hif.ctrl_ready)) + ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, 0); + else + ctrl_reg = 0; + if (!(ctrl_reg & CTRL_NEXT_LEN_MASK)) + return i; + // ctrl_reg units are 16bits words + len = (ctrl_reg & CTRL_NEXT_LEN_MASK) * 2; + piggyback = rx_helper(wdev, len, num_cnf); + if (piggyback < 0) + return i; + if (!(piggyback & CTRL_WLAN_READY)) + dev_err(wdev->dev, "unexpected piggyback value: ready bit not set: %04x\n", + piggyback); + } + if (piggyback & CTRL_NEXT_LEN_MASK) { + ctrl_reg = atomic_xchg(&wdev->hif.ctrl_reg, piggyback); + complete(&wdev->hif.ctrl_ready); + if (ctrl_reg) + dev_err(wdev->dev, "unexpected IRQ happened: %04x/%04x\n", + ctrl_reg, piggyback); + } + return i; +} + +static void tx_helper(struct wfx_dev *wdev, struct hif_msg *hif) +{ + int ret; + void *data; + bool is_encrypted = false; + size_t len = le16_to_cpu(hif->len); + + WARN(len < sizeof(*hif), "try to send corrupted data"); + + hif->seqnum = wdev->hif.tx_seqnum; + wdev->hif.tx_seqnum = (wdev->hif.tx_seqnum + 1) % (HIF_COUNTER_MAX + 1); + + data = hif; + WARN(len > wdev->hw_caps.size_inp_ch_buf, + "%s: request exceed WFx capability: %zu > %d\n", __func__, + len, wdev->hw_caps.size_inp_ch_buf); + len = wdev->hwbus_ops->align_size(wdev->hwbus_priv, len); + ret = wfx_data_write(wdev, data, len); + if (ret) + goto end; + + wdev->hif.tx_buffers_used++; + _trace_hif_send(hif, wdev->hif.tx_buffers_used); +end: + if (is_encrypted) + kfree(data); +} + +static int bh_work_tx(struct wfx_dev *wdev, int max_msg) +{ + struct hif_msg *hif; + int i; + + for (i = 0; i < max_msg; i++) { + hif = NULL; + if (wdev->hif.tx_buffers_used < wdev->hw_caps.num_inp_ch_bufs) { + if (try_wait_for_completion(&wdev->hif_cmd.ready)) { + WARN(!mutex_is_locked(&wdev->hif_cmd.lock), "data locking error"); + hif = wdev->hif_cmd.buf_send; + } else { + hif = wfx_tx_queues_get(wdev); + } + } + if (!hif) + return i; + tx_helper(wdev, hif); + } + return i; +} + +/* In SDIO mode, it is necessary to make an access to a register to acknowledge + * last received message. It could be possible to restrict this acknowledge to + * SDIO mode and only if last operation was rx. + */ +static void ack_sdio_data(struct wfx_dev *wdev) +{ + u32 cfg_reg; + + config_reg_read(wdev, &cfg_reg); + if (cfg_reg & 0xFF) { + dev_warn(wdev->dev, "chip reports errors: %02x\n", + cfg_reg & 0xFF); + config_reg_write_bits(wdev, 0xFF, 0x00); + } +} + +static void bh_work(struct work_struct *work) +{ + struct wfx_dev *wdev = container_of(work, struct wfx_dev, hif.bh); + int stats_req = 0, stats_cnf = 0, stats_ind = 0; + bool release_chip = false, last_op_is_rx = false; + int num_tx, num_rx; + + device_wakeup(wdev); + do { + num_tx = bh_work_tx(wdev, 32); + stats_req += num_tx; + if (num_tx) + last_op_is_rx = false; + num_rx = bh_work_rx(wdev, 32, &stats_cnf); + stats_ind += num_rx; + if (num_rx) + last_op_is_rx = true; + } while (num_rx || num_tx); + stats_ind -= stats_cnf; + + if (last_op_is_rx) + ack_sdio_data(wdev); + if (!wdev->hif.tx_buffers_used && !work_pending(work)) { + device_release(wdev); + release_chip = true; + } + _trace_bh_stats(stats_ind, stats_req, stats_cnf, + wdev->hif.tx_buffers_used, release_chip); +} + +/* + * An IRQ from chip did occur + */ +void wfx_bh_request_rx(struct wfx_dev *wdev) +{ + u32 cur, prev; + + control_reg_read(wdev, &cur); + prev = atomic_xchg(&wdev->hif.ctrl_reg, cur); + complete(&wdev->hif.ctrl_ready); + queue_work(system_highpri_wq, &wdev->hif.bh); + + if (!(cur & CTRL_NEXT_LEN_MASK)) + dev_err(wdev->dev, "unexpected control register value: length field is 0: %04x\n", + cur); + if (prev != 0) + dev_err(wdev->dev, "received IRQ but previous data was not (yet) read: %04x/%04x\n", + prev, cur); +} + +/* + * Driver want to send data + */ +void wfx_bh_request_tx(struct wfx_dev *wdev) +{ + queue_work(system_highpri_wq, &wdev->hif.bh); +} + +/* + * If IRQ is not available, this function allow to manually poll the control + * register and simulate an IRQ ahen an event happened. + * + * Note that the device has a bug: If an IRQ raise while host read control + * register, the IRQ is lost. So, use this function carefully (only duing + * device initialisation). + */ +void wfx_bh_poll_irq(struct wfx_dev *wdev) +{ + ktime_t now, start; + u32 reg; + + WARN(!wdev->poll_irq, "unexpected IRQ polling can mask IRQ"); + start = ktime_get(); + for (;;) { + control_reg_read(wdev, ®); + now = ktime_get(); + if (reg & 0xFFF) + break; + if (ktime_after(now, ktime_add_ms(start, 1000))) { + dev_err(wdev->dev, "time out while polling control register\n"); + return; + } + udelay(200); + } + wfx_bh_request_rx(wdev); +} + +void wfx_bh_register(struct wfx_dev *wdev) +{ + INIT_WORK(&wdev->hif.bh, bh_work); + init_completion(&wdev->hif.ctrl_ready); + init_waitqueue_head(&wdev->hif.tx_buffers_empty); +} + +void wfx_bh_unregister(struct wfx_dev *wdev) +{ + flush_work(&wdev->hif.bh); +} diff --git a/drivers/net/wireless/silabs/wfx/bh.h b/drivers/net/wireless/silabs/wfx/bh.h new file mode 100644 index 000000000000..78c49329e22a --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/bh.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Interrupt bottom half. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_BH_H +#define WFX_BH_H + +#include +#include +#include + +struct wfx_dev; + +struct wfx_hif { + struct work_struct bh; + struct completion ctrl_ready; + wait_queue_head_t tx_buffers_empty; + atomic_t ctrl_reg; + int rx_seqnum; + int tx_seqnum; + int tx_buffers_used; +}; + +void wfx_bh_register(struct wfx_dev *wdev); +void wfx_bh_unregister(struct wfx_dev *wdev); +void wfx_bh_request_rx(struct wfx_dev *wdev); +void wfx_bh_request_tx(struct wfx_dev *wdev); +void wfx_bh_poll_irq(struct wfx_dev *wdev); + +#endif /* WFX_BH_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:03 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:03 +0100 Subject: [PATCH v3 20/24] wfx: add scan.c/scan.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-21-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/scan.c | 132 +++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/scan.h | 22 +++++ 2 files changed, 154 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/scan.c create mode 100644 drivers/net/wireless/silabs/wfx/scan.h diff --git a/drivers/net/wireless/silabs/wfx/scan.c b/drivers/net/wireless/silabs/wfx/scan.c new file mode 100644 index 000000000000..fb47c7cddf2f --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/scan.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Scan related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include + +#include "scan.h" +#include "wfx.h" +#include "sta.h" +#include "hif_tx_mib.h" + +static void __ieee80211_scan_completed_compat(struct ieee80211_hw *hw, + bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted, + }; + + ieee80211_scan_completed(hw, &info); +} + +static int update_probe_tmpl(struct wfx_vif *wvif, + struct cfg80211_scan_request *req) +{ + struct sk_buff *skb; + + skb = ieee80211_probereq_get(wvif->wdev->hw, wvif->vif->addr, + NULL, 0, req->ie_len); + if (!skb) + return -ENOMEM; + + skb_put_data(skb, req->ie, req->ie_len); + hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBREQ, 0); + dev_kfree_skb(skb); + return 0; +} + +static int send_scan_req(struct wfx_vif *wvif, + struct cfg80211_scan_request *req, int start_idx) +{ + int i, ret, timeout; + struct ieee80211_channel *ch_start, *ch_cur; + + for (i = start_idx; i < req->n_channels; i++) { + ch_start = req->channels[start_idx]; + ch_cur = req->channels[i]; + WARN(ch_cur->band != NL80211_BAND_2GHZ, "band not supported"); + if (ch_cur->max_power != ch_start->max_power) + break; + if ((ch_cur->flags ^ ch_start->flags) & IEEE80211_CHAN_NO_IR) + break; + } + wfx_tx_lock_flush(wvif->wdev); + wvif->scan_abort = false; + reinit_completion(&wvif->scan_complete); + ret = hif_scan(wvif, req, start_idx, i - start_idx, &timeout); + if (ret) { + wfx_tx_unlock(wvif->wdev); + return -EIO; + } + ret = wait_for_completion_timeout(&wvif->scan_complete, timeout); + if (req->channels[start_idx]->max_power != wvif->vif->bss_conf.txpower) + hif_set_output_power(wvif, wvif->vif->bss_conf.txpower); + wfx_tx_unlock(wvif->wdev); + if (!ret) { + dev_notice(wvif->wdev->dev, "scan timeout\n"); + hif_stop_scan(wvif); + return -ETIMEDOUT; + } + if (wvif->scan_abort) { + dev_notice(wvif->wdev->dev, "scan abort\n"); + return -ECONNABORTED; + } + return i - start_idx; +} + +/* + * It is not really necessary to run scan request asynchronously. However, + * there is a bug in "iw scan" when ieee80211_scan_completed() is called before + * wfx_hw_scan() return + */ +void wfx_hw_scan_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, scan_work); + struct ieee80211_scan_request *hw_req = wvif->scan_req; + int chan_cur, ret; + + mutex_lock(&wvif->wdev->conf_mutex); + mutex_lock(&wvif->scan_lock); + if (wvif->join_in_progress) { + dev_info(wvif->wdev->dev, "%s: abort in-progress REQ_JOIN", + __func__); + wfx_reset(wvif); + } + update_probe_tmpl(wvif, &hw_req->req); + chan_cur = 0; + do { + ret = send_scan_req(wvif, &hw_req->req, chan_cur); + if (ret > 0) + chan_cur += ret; + } while (ret > 0 && chan_cur < hw_req->req.n_channels); + mutex_unlock(&wvif->scan_lock); + mutex_unlock(&wvif->wdev->conf_mutex); + __ieee80211_scan_completed_compat(wvif->wdev->hw, ret < 0); +} + +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + WARN_ON(hw_req->req.n_channels > HIF_API_MAX_NB_CHANNELS); + wvif->scan_req = hw_req; + schedule_work(&wvif->scan_work); + return 0; +} + +void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wvif->scan_abort = true; + hif_stop_scan(wvif); +} + +void wfx_scan_complete(struct wfx_vif *wvif) +{ + complete(&wvif->scan_complete); +} diff --git a/drivers/net/wireless/silabs/wfx/scan.h b/drivers/net/wireless/silabs/wfx/scan.h new file mode 100644 index 000000000000..c7496a766478 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/scan.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Scan related functions. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_SCAN_H +#define WFX_SCAN_H + +#include + +struct wfx_dev; +struct wfx_vif; + +void wfx_hw_scan_work(struct work_struct *work); +int wfx_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_scan_request *req); +void wfx_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_scan_complete(struct wfx_vif *wvif); + +#endif /* WFX_SCAN_H */ -- 2.28.0 From Jerome.Pouiller at silabs.com Wed Nov 4 15:52:02 2020 From: Jerome.Pouiller at silabs.com (Jerome Pouiller) Date: Wed, 4 Nov 2020 16:52:02 +0100 Subject: [PATCH v3 19/24] wfx: add sta.c/sta.h In-Reply-To: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> Message-ID: <20201104155207.128076-20-Jerome.Pouiller@silabs.com> From: J?r?me Pouiller Signed-off-by: J?r?me Pouiller --- drivers/net/wireless/silabs/wfx/sta.c | 807 ++++++++++++++++++++++++++ drivers/net/wireless/silabs/wfx/sta.h | 73 +++ 2 files changed, 880 insertions(+) create mode 100644 drivers/net/wireless/silabs/wfx/sta.c create mode 100644 drivers/net/wireless/silabs/wfx/sta.h diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c new file mode 100644 index 000000000000..196779a1b89a --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -0,0 +1,807 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#include +#include + +#include "sta.h" +#include "wfx.h" +#include "fwio.h" +#include "bh.h" +#include "key.h" +#include "scan.h" +#include "debug.h" +#include "hif_tx.h" +#include "hif_tx_mib.h" + +#define HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES 2 + +u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates) +{ + int i; + u32 ret = 0; + // WFx only support 2GHz + struct ieee80211_supported_band *sband = wdev->hw->wiphy->bands[NL80211_BAND_2GHZ]; + + for (i = 0; i < sband->n_bitrates; i++) { + if (rates & BIT(i)) { + if (i >= sband->n_bitrates) + dev_warn(wdev->dev, "unsupported basic rate\n"); + else + ret |= BIT(sband->bitrates[i].hw_value); + } + } + return ret; +} + +void wfx_cooling_timeout_work(struct work_struct *work) +{ + struct wfx_dev *wdev = container_of(to_delayed_work(work), + struct wfx_dev, + cooling_timeout_work); + + wdev->chip_frozen = true; + wfx_tx_unlock(wdev); +} + +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd) +{ + if (cmd == STA_NOTIFY_AWAKE) { + // Device recover normal temperature + if (cancel_delayed_work(&wdev->cooling_timeout_work)) + wfx_tx_unlock(wdev); + } else { + // Device is too hot + schedule_delayed_work(&wdev->cooling_timeout_work, 10 * HZ); + wfx_tx_lock(wdev); + } +} + +static void wfx_filter_beacon(struct wfx_vif *wvif, bool filter_beacon) +{ + static const struct hif_ie_table_entry filter_ies[] = { + { + .ie_id = WLAN_EID_VENDOR_SPECIFIC, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + .oui = { 0x50, 0x6F, 0x9A }, + }, { + .ie_id = WLAN_EID_HT_OPERATION, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + }, { + .ie_id = WLAN_EID_ERP_INFO, + .has_changed = 1, + .no_longer = 1, + .has_appeared = 1, + } + }; + + if (!filter_beacon) { + hif_beacon_filter_control(wvif, 0, 1); + } else { + hif_set_beacon_filter_table(wvif, 3, filter_ies); + hif_beacon_filter_control(wvif, HIF_BEACON_FILTER_ENABLE, 0); + } +} + +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused) +{ + struct wfx_vif *wvif = NULL; + struct wfx_dev *wdev = hw->priv; + bool filter_bssid, filter_prbreq, filter_beacon; + + // Notes: + // - Probe responses (FIF_BCN_PRBRESP_PROMISC) are never filtered + // - PS-Poll (FIF_PSPOLL) are never filtered + // - RTS, CTS and Ack (FIF_CONTROL) are always filtered + // - Broken frames (FIF_FCSFAIL and FIF_PLCPFAIL) are always filtered + // - Firmware does (yet) allow to forward unicast traffic sent to + // other stations (aka. promiscuous mode) + *total_flags &= FIF_BCN_PRBRESP_PROMISC | FIF_ALLMULTI | FIF_OTHER_BSS | + FIF_PROBE_REQ | FIF_PSPOLL; + + mutex_lock(&wdev->conf_mutex); + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + mutex_lock(&wvif->scan_lock); + + // Note: FIF_BCN_PRBRESP_PROMISC covers probe response and + // beacons from other BSS + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + filter_beacon = false; + else + filter_beacon = true; + wfx_filter_beacon(wvif, filter_beacon); + + if (*total_flags & FIF_OTHER_BSS) + filter_bssid = false; + else + filter_bssid = true; + + // In AP mode, chip can reply to probe request itself + if (*total_flags & FIF_PROBE_REQ && + wvif->vif->type == NL80211_IFTYPE_AP) { + dev_dbg(wdev->dev, "do not forward probe request in AP mode\n"); + *total_flags &= ~FIF_PROBE_REQ; + } + + if (*total_flags & FIF_PROBE_REQ) + filter_prbreq = false; + else + filter_prbreq = true; + hif_set_rx_filter(wvif, filter_bssid, filter_prbreq); + + mutex_unlock(&wvif->scan_lock); + } + mutex_unlock(&wdev->conf_mutex); +} + +static int wfx_get_ps_timeout(struct wfx_vif *wvif, bool *enable_ps) +{ + struct ieee80211_channel *chan0 = NULL, *chan1 = NULL; + struct ieee80211_conf *conf = &wvif->wdev->hw->conf; + + WARN(!wvif->vif->bss_conf.assoc && enable_ps, + "enable_ps is reliable only if associated"); + if (wdev_to_wvif(wvif->wdev, 0)) + chan0 = wdev_to_wvif(wvif->wdev, 0)->vif->bss_conf.chandef.chan; + if (wdev_to_wvif(wvif->wdev, 1)) + chan1 = wdev_to_wvif(wvif->wdev, 1)->vif->bss_conf.chandef.chan; + if (chan0 && chan1 && chan0->hw_value != chan1->hw_value && + wvif->vif->type != NL80211_IFTYPE_AP) { + // It is necessary to enable powersave if channels + // are different. + if (enable_ps) + *enable_ps = true; + if (wvif->wdev->force_ps_timeout > -1) + return wvif->wdev->force_ps_timeout; + else if (wfx_api_older_than(wvif->wdev, 3, 2)) + return 0; + else + return 30; + } + if (enable_ps) + *enable_ps = wvif->vif->bss_conf.ps; + if (wvif->wdev->force_ps_timeout > -1) + return wvif->wdev->force_ps_timeout; + else if (wvif->vif->bss_conf.assoc && wvif->vif->bss_conf.ps) + return conf->dynamic_ps_timeout; + else + return -1; +} + +int wfx_update_pm(struct wfx_vif *wvif) +{ + int ps_timeout; + bool ps; + + if (!wvif->vif->bss_conf.assoc) + return 0; + ps_timeout = wfx_get_ps_timeout(wvif, &ps); + if (!ps) + ps_timeout = 0; + WARN_ON(ps_timeout < 0); + if (wvif->uapsd_mask) + ps_timeout = 0; + + if (!wait_for_completion_timeout(&wvif->set_pm_mode_complete, + TU_TO_JIFFIES(512))) + dev_warn(wvif->wdev->dev, + "timeout while waiting of set_pm_mode_complete\n"); + return hif_set_pm(wvif, ps, ps_timeout); +} + +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + int old_uapsd = wvif->uapsd_mask; + + WARN_ON(queue >= hw->queues); + + mutex_lock(&wdev->conf_mutex); + assign_bit(queue, &wvif->uapsd_mask, params->uapsd); + hif_set_edca_queue_params(wvif, queue, params); + if (wvif->vif->type == NL80211_IFTYPE_STATION && + old_uapsd != wvif->uapsd_mask) { + hif_set_uapsd_info(wvif, wvif->uapsd_mask); + wfx_update_pm(wvif); + } + mutex_unlock(&wdev->conf_mutex); + return 0; +} + +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = NULL; + + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + hif_rts_threshold(wvif, value); + return 0; +} + +/* WSM callbacks */ + +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi) +{ + /* RSSI: signed Q8.0, RCPI: unsigned Q7.1 + * RSSI = RCPI / 2 - 110 + */ + int rcpi_rssi; + int cqm_evt; + + rcpi_rssi = raw_rcpi_rssi / 2 - 110; + if (rcpi_rssi <= wvif->vif->bss_conf.cqm_rssi_thold) + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW; + else + cqm_evt = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; + ieee80211_cqm_rssi_notify(wvif->vif, cqm_evt, rcpi_rssi, GFP_KERNEL); +} + +static void wfx_beacon_loss_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(to_delayed_work(work), + struct wfx_vif, beacon_loss_work); + struct ieee80211_bss_conf *bss_conf = &wvif->vif->bss_conf; + + ieee80211_beacon_loss(wvif->vif); + schedule_delayed_work(to_delayed_work(work), + msecs_to_jiffies(bss_conf->beacon_int)); +} + +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + hif_wep_default_key_id(wvif, idx); +} + +void wfx_reset(struct wfx_vif *wvif) +{ + struct wfx_dev *wdev = wvif->wdev; + + wfx_tx_lock_flush(wdev); + hif_reset(wvif, false); + wfx_tx_policy_init(wvif); + if (wvif_count(wdev) <= 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + wfx_tx_unlock(wdev); + wvif->join_in_progress = false; + cancel_delayed_work_sync(&wvif->beacon_loss_work); + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); +} + +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; + + sta_priv->vif_id = wvif->id; + + if (vif->type == NL80211_IFTYPE_STATION) + hif_set_mfp(wvif, sta->mfp, sta->mfp); + + // In station mode, the firmware interprets new link-id as a TDLS peer. + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) + return 0; + sta_priv->link_id = ffz(wvif->link_id_map); + wvif->link_id_map |= BIT(sta_priv->link_id); + WARN_ON(!sta_priv->link_id); + WARN_ON(sta_priv->link_id >= HIF_LINK_ID_MAX); + hif_map_link(wvif, false, sta->addr, sta_priv->link_id, sta->mfp); + + return 0; +} + +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_sta_priv *sta_priv = (struct wfx_sta_priv *)&sta->drv_priv; + + // See note in wfx_sta_add() + if (!sta_priv->link_id) + return 0; + // FIXME add a mutex? + hif_map_link(wvif, true, sta->addr, sta_priv->link_id, false); + wvif->link_id_map &= ~BIT(sta_priv->link_id); + return 0; +} + +static int wfx_upload_ap_templates(struct wfx_vif *wvif) +{ + struct sk_buff *skb; + + skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); + if (!skb) + return -ENOMEM; + hif_set_template_frame(wvif, skb, HIF_TMPLT_BCN, + API_RATE_INDEX_B_1MBPS); + dev_kfree_skb(skb); + + skb = ieee80211_proberesp_get(wvif->wdev->hw, wvif->vif); + if (!skb) + return -ENOMEM; + hif_set_template_frame(wvif, skb, HIF_TMPLT_PRBRES, + API_RATE_INDEX_B_1MBPS); + dev_kfree_skb(skb); + return 0; +} + +static void wfx_set_mfp_ap(struct wfx_vif *wvif) +{ + struct sk_buff *skb = ieee80211_beacon_get(wvif->wdev->hw, wvif->vif); + const int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable); + const u16 *ptr = (u16 *)cfg80211_find_ie(WLAN_EID_RSN, + skb->data + ieoffset, + skb->len - ieoffset); + const int pairwise_cipher_suite_count_offset = 8 / sizeof(u16); + const int pairwise_cipher_suite_size = 4 / sizeof(u16); + const int akm_suite_size = 4 / sizeof(u16); + + if (ptr) { + ptr += pairwise_cipher_suite_count_offset; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + ptr += 1 + pairwise_cipher_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + ptr += 1 + akm_suite_size * *ptr; + if (WARN_ON(ptr > (u16 *)skb_tail_pointer(skb))) + return; + hif_set_mfp(wvif, *ptr & BIT(7), *ptr & BIT(6)); + } +} + +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct wfx_dev *wdev = wvif->wdev; + int ret; + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) + wfx_update_pm(wvif); + wvif = (struct wfx_vif *)vif->drv_priv; + wfx_upload_ap_templates(wvif); + ret = hif_start(wvif, &vif->bss_conf, wvif->channel); + if (ret > 0) + return -EIO; + wfx_set_mfp_ap(wvif); + return ret; +} + +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_reset(wvif); +} + +static void wfx_join(struct wfx_vif *wvif) +{ + int ret; + struct ieee80211_bss_conf *conf = &wvif->vif->bss_conf; + struct cfg80211_bss *bss = NULL; + u8 ssid[IEEE80211_MAX_SSID_LEN]; + const u8 *ssidie = NULL; + int ssidlen = 0; + + wfx_tx_lock_flush(wvif->wdev); + + bss = cfg80211_get_bss(wvif->wdev->hw->wiphy, wvif->channel, + conf->bssid, NULL, 0, + IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); + if (!bss && !conf->ibss_joined) { + wfx_tx_unlock(wvif->wdev); + return; + } + + rcu_read_lock(); // protect ssidie + if (bss) + ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); + if (ssidie) { + ssidlen = ssidie[1]; + if (ssidlen > IEEE80211_MAX_SSID_LEN) + ssidlen = IEEE80211_MAX_SSID_LEN; + memcpy(ssid, &ssidie[2], ssidlen); + } + rcu_read_unlock(); + + cfg80211_put_bss(wvif->wdev->hw->wiphy, bss); + + wvif->join_in_progress = true; + ret = hif_join(wvif, conf, wvif->channel, ssid, ssidlen); + if (ret) { + ieee80211_connection_loss(wvif->vif); + wfx_reset(wvif); + } else { + /* Due to beacon filtering it is possible that the + * AP's beacon is not known for the mac80211 stack. + * Disable filtering temporary to make sure the stack + * receives at least one + */ + wfx_filter_beacon(wvif, false); + } + wfx_tx_unlock(wvif->wdev); +} + +static void wfx_join_finalize(struct wfx_vif *wvif, + struct ieee80211_bss_conf *info) +{ + struct ieee80211_sta *sta = NULL; + int ampdu_density = 0; + bool greenfield = false; + + rcu_read_lock(); // protect sta + if (info->bssid && !info->ibss_joined) + sta = ieee80211_find_sta(wvif->vif, info->bssid); + if (sta && sta->ht_cap.ht_supported) + ampdu_density = sta->ht_cap.ampdu_density; + if (sta && sta->ht_cap.ht_supported && + !(info->ht_operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)) + greenfield = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD); + rcu_read_unlock(); + + wvif->join_in_progress = false; + hif_set_association_mode(wvif, ampdu_density, greenfield, + info->use_short_preamble); + hif_keep_alive_period(wvif, 0); + // beacon_loss_count is defined to 7 in net/mac80211/mlme.c. Let's use + // the same value. + hif_set_bss_params(wvif, info->aid, 7); + hif_set_beacon_wakeup_period(wvif, 1, 1); + wfx_update_pm(wvif); +} + +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_upload_ap_templates(wvif); + wfx_join(wvif); + return 0; +} + +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wfx_reset(wvif); +} + +static void wfx_enable_beacon(struct wfx_vif *wvif, bool enable) +{ + // Driver has Content After DTIM Beacon in queue. Driver is waiting for + // a signal from the firmware. Since we are going to stop to send + // beacons, this signal will never happens. See also + // wfx_suspend_resume_mc() + if (!enable && wfx_tx_queues_has_cab(wvif)) { + wvif->after_dtim_tx_allowed = true; + wfx_bh_request_tx(wvif->wdev); + } + hif_beacon_transmit(wvif, enable); +} + +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + int i; + + mutex_lock(&wdev->conf_mutex); + + if (changed & BSS_CHANGED_BASIC_RATES || + changed & BSS_CHANGED_BEACON_INT || + changed & BSS_CHANGED_BSSID) { + if (vif->type == NL80211_IFTYPE_STATION) + wfx_join(wvif); + } + + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc || info->ibss_joined) + wfx_join_finalize(wvif, info); + else if (!info->assoc && vif->type == NL80211_IFTYPE_STATION) + wfx_reset(wvif); + else + dev_warn(wdev->dev, "%s: misunderstood change: ASSOC\n", + __func__); + } + + if (changed & BSS_CHANGED_BEACON_INFO) { + if (vif->type != NL80211_IFTYPE_STATION) + dev_warn(wdev->dev, "%s: misunderstood change: BEACON_INFO\n", + __func__); + hif_set_beacon_wakeup_period(wvif, info->dtim_period, + info->dtim_period); + // We temporary forwarded beacon for join process. It is now no + // more necessary. + wfx_filter_beacon(wvif, true); + } + + if (changed & BSS_CHANGED_ARP_FILTER) { + for (i = 0; i < HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES; i++) { + __be32 *arp_addr = &info->arp_addr_list[i]; + + if (info->arp_addr_cnt > HIF_MAX_ARP_IP_ADDRTABLE_ENTRIES) + arp_addr = NULL; + if (i >= info->arp_addr_cnt) + arp_addr = NULL; + hif_set_arp_ipv4_filter(wvif, i, arp_addr); + } + } + + if (changed & BSS_CHANGED_AP_PROBE_RESP || + changed & BSS_CHANGED_BEACON) + wfx_upload_ap_templates(wvif); + + if (changed & BSS_CHANGED_BEACON_ENABLED) + wfx_enable_beacon(wvif, info->enable_beacon); + + if (changed & BSS_CHANGED_KEEP_ALIVE) + hif_keep_alive_period(wvif, info->max_idle_period * + USEC_PER_TU / USEC_PER_MSEC); + + if (changed & BSS_CHANGED_ERP_CTS_PROT) + hif_erp_use_protection(wvif, info->use_cts_prot); + + if (changed & BSS_CHANGED_ERP_SLOT) + hif_slot_time(wvif, info->use_short_slot ? 9 : 20); + + if (changed & BSS_CHANGED_CQM) + hif_set_rcpi_rssi_threshold(wvif, info->cqm_rssi_thold, + info->cqm_rssi_hyst); + + if (changed & BSS_CHANGED_TXPOWER) + hif_set_output_power(wvif, info->txpower); + + if (changed & BSS_CHANGED_PS) + wfx_update_pm(wvif); + + mutex_unlock(&wdev->conf_mutex); +} + +static int wfx_update_tim(struct wfx_vif *wvif) +{ + struct sk_buff *skb; + u16 tim_offset, tim_length; + u8 *tim_ptr; + + skb = ieee80211_beacon_get_tim(wvif->wdev->hw, wvif->vif, + &tim_offset, &tim_length); + if (!skb) + return -ENOENT; + tim_ptr = skb->data + tim_offset; + + if (tim_offset && tim_length >= 6) { + /* Ignore DTIM count from mac80211: + * firmware handles DTIM internally. + */ + tim_ptr[2] = 0; + + /* Set/reset aid0 bit */ + if (wfx_tx_queues_has_cab(wvif)) + tim_ptr[4] |= 1; + else + tim_ptr[4] &= ~1; + } + + hif_update_ie_beacon(wvif, tim_ptr, tim_length); + dev_kfree_skb(skb); + + return 0; +} + +static void wfx_update_tim_work(struct work_struct *work) +{ + struct wfx_vif *wvif = container_of(work, struct wfx_vif, update_tim_work); + + wfx_update_tim(wvif); +} + +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_sta_priv *sta_dev = (struct wfx_sta_priv *)&sta->drv_priv; + struct wfx_vif *wvif = wdev_to_wvif(wdev, sta_dev->vif_id); + + if (!wvif) { + dev_warn(wdev->dev, "%s: received event for non-existent vif\n", __func__); + return -EIO; + } + schedule_work(&wvif->update_tim_work); + return 0; +} + +void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd notify_cmd) +{ + if (notify_cmd != STA_NOTIFY_AWAKE) + return; + WARN(!wfx_tx_queues_has_cab(wvif), "incorrect sequence"); + WARN(wvif->after_dtim_tx_allowed, "incorrect sequence"); + wvif->after_dtim_tx_allowed = true; + wfx_bh_request_tx(wvif->wdev); +} + +int wfx_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + // Aggregation is implemented fully in firmware + switch (params->action) { + case IEEE80211_AMPDU_RX_START: + case IEEE80211_AMPDU_RX_STOP: + // Just acknowledge it to enable frame re-ordering + return 0; + default: + // Leave the firmware doing its business for tx aggregation + return -ENOTSUPP; + } +} + +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ + return 0; +} + +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf) +{ +} + +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, + u32 changed) +{ +} + +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel, "channel overwrite"); + wvif->channel = ch; + + return 0; +} + +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf) +{ + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + struct ieee80211_channel *ch = conf->def.chan; + + WARN(wvif->channel != ch, "channel mismatch"); + wvif->channel = NULL; +} + +int wfx_config(struct ieee80211_hw *hw, u32 changed) +{ + return 0; +} + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + int i, ret = 0; + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | + IEEE80211_VIF_SUPPORTS_UAPSD | + IEEE80211_VIF_SUPPORTS_CQM_RSSI; + + mutex_lock(&wdev->conf_mutex); + + switch (vif->type) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + break; + default: + mutex_unlock(&wdev->conf_mutex); + return -EOPNOTSUPP; + } + + // FIXME: prefer use of container_of() to get vif + wvif->vif = vif; + wvif->wdev = wdev; + + wvif->link_id_map = 1; // link-id 0 is reserved for multicast + INIT_WORK(&wvif->update_tim_work, wfx_update_tim_work); + INIT_DELAYED_WORK(&wvif->beacon_loss_work, wfx_beacon_loss_work); + + init_completion(&wvif->set_pm_mode_complete); + complete(&wvif->set_pm_mode_complete); + INIT_WORK(&wvif->tx_policy_upload_work, wfx_tx_policy_upload_work); + + mutex_init(&wvif->scan_lock); + init_completion(&wvif->scan_complete); + INIT_WORK(&wvif->scan_work, wfx_hw_scan_work); + + wfx_tx_queues_init(wvif); + wfx_tx_policy_init(wvif); + + for (i = 0; i < ARRAY_SIZE(wdev->vif); i++) { + if (!wdev->vif[i]) { + wdev->vif[i] = vif; + wvif->id = i; + break; + } + } + WARN(i == ARRAY_SIZE(wdev->vif), "try to instantiate more vif than supported"); + + hif_set_macaddr(wvif, vif->addr); + + mutex_unlock(&wdev->conf_mutex); + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + } + return ret; +} + +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct wfx_dev *wdev = hw->priv; + struct wfx_vif *wvif = (struct wfx_vif *)vif->drv_priv; + + wait_for_completion_timeout(&wvif->set_pm_mode_complete, msecs_to_jiffies(300)); + wfx_tx_queues_check_empty(wvif); + + mutex_lock(&wdev->conf_mutex); + WARN(wvif->link_id_map != 1, "corrupted state"); + + hif_reset(wvif, false); + hif_set_macaddr(wvif, NULL); + wfx_tx_policy_init(wvif); + + cancel_delayed_work_sync(&wvif->beacon_loss_work); + wdev->vif[wvif->id] = NULL; + wvif->vif = NULL; + + mutex_unlock(&wdev->conf_mutex); + + wvif = NULL; + while ((wvif = wvif_iterate(wdev, wvif)) != NULL) { + // Combo mode does not support Block Acks. We can re-enable them + if (wvif_count(wdev) == 1) + hif_set_block_ack_policy(wvif, 0xFF, 0xFF); + else + hif_set_block_ack_policy(wvif, 0x00, 0x00); + } +} + +int wfx_start(struct ieee80211_hw *hw) +{ + return 0; +} + +void wfx_stop(struct ieee80211_hw *hw) +{ + struct wfx_dev *wdev = hw->priv; + + WARN_ON(!skb_queue_empty_lockless(&wdev->tx_pending)); +} diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h new file mode 100644 index 000000000000..d7b5df5ea4e6 --- /dev/null +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Implementation of mac80211 API. + * + * Copyright (c) 2017-2020, Silicon Laboratories, Inc. + * Copyright (c) 2010, ST-Ericsson + */ +#ifndef WFX_STA_H +#define WFX_STA_H + +#include + +struct wfx_dev; +struct wfx_vif; + +struct wfx_sta_priv { + int link_id; + int vif_id; +}; + +// mac80211 interface +int wfx_start(struct ieee80211_hw *hw); +void wfx_stop(struct ieee80211_hw *hw); +int wfx_config(struct ieee80211_hw *hw, u32 changed); +int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +void wfx_set_default_unicast_key(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, int idx); +void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, + unsigned int *total_flags, u64 unused); + +int wfx_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_join_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +void wfx_leave_ibss(struct ieee80211_hw *hw, struct ieee80211_vif *vif); +int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u16 queue, const struct ieee80211_tx_queue_params *params); +void wfx_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, u32 changed); +int wfx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +int wfx_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); +void wfx_sta_notify(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + enum sta_notify_cmd cmd, struct ieee80211_sta *sta); +int wfx_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); +int wfx_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params); +int wfx_add_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_remove_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf); +void wfx_change_chanctx(struct ieee80211_hw *hw, + struct ieee80211_chanctx_conf *conf, u32 changed); +int wfx_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); +void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_chanctx_conf *conf); + +// WSM Callbacks +void wfx_cooling_timeout_work(struct work_struct *work); +void wfx_suspend_hot_dev(struct wfx_dev *wdev, enum sta_notify_cmd cmd); +void wfx_suspend_resume_mc(struct wfx_vif *wvif, enum sta_notify_cmd cmd); +void wfx_event_report_rssi(struct wfx_vif *wvif, u8 raw_rcpi_rssi); +int wfx_update_pm(struct wfx_vif *wvif); + +// Other Helpers +void wfx_reset(struct wfx_vif *wvif); +u32 wfx_rate_mask_to_hw(struct wfx_dev *wdev, u32 rates); + +#endif /* WFX_STA_H */ -- 2.28.0 From helen.koike at collabora.com Wed Nov 4 16:36:49 2020 From: helen.koike at collabora.com (Helen Koike) Date: Wed, 4 Nov 2020 13:36:49 -0300 Subject: [PATCH 00/14] Allwinner MIPI CSI-2 support for A31/V3s/A83T In-Reply-To: <20201104111137.GH285779@aptenodytes> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201104111137.GH285779@aptenodytes> Message-ID: Hi Paul, On 11/4/20 8:11 AM, Paul Kocialkowski wrote: > Hi Helen, > > On Fri 30 Oct 20, 19:44, Helen Koike wrote: >> Hi Paul, >> >> I have some comments through the series, I hope this helps. > > Thanks for your comments :) > >> On 10/23/20 2:45 PM, Paul Kocialkowski wrote: >>> This series introduces support for MIPI CSI-2, with the A31 controller that is >>> found on most SoCs (A31, V3s and probably V5) as well as the A83T-specific >>> controller. While the former uses the same MIPI D-PHY that is already supported >>> for DSI, the latter embeds its own D-PHY. >>> >>> In order to distinguish the use of the D-PHY between Rx mode (for MIPI CSI-2) >>> and Tx mode (for MIPI DSI), a submode is introduced for D-PHY in the PHY API. >>> This allows adding Rx support in the A31 D-PHY driver. >>> >>> A few changes and fixes are applied to the A31 CSI controller driver, in order >>> to support the MIPI CSI-2 use-case. >>> >>> Follows is the V4L2 device topology representing the interactions between >>> the MIPI CSI-2 sensor, the MIPI CSI-2 controller (which controls the D-PHY) >>> and the CSI controller: >>> - entity 1: sun6i-csi (1 pad, 1 link) >>> type Node subtype V4L flags 0 >>> device node name /dev/video0 >>> pad0: Sink >>> <- "sun6i-mipi-csi2":1 [ENABLED,IMMUTABLE] >>> >>> - entity 5: sun6i-mipi-csi2 (2 pads, 2 links) >>> type V4L2 subdev subtype Unknown flags 0 >>> pad0: Sink >>> <- "ov5648 0-0036":0 [ENABLED,IMMUTABLE] >>> pad1: Source >>> -> "sun6i-csi":0 [ENABLED,IMMUTABLE] >>> >>> - entity 8: ov5648 0-0036 (1 pad, 1 link) >>> type V4L2 subdev subtype Sensor flags 0 >>> device node name /dev/v4l-subdev0 >> >> Question: I noticed is that sun6i-mipi-csi2 doesn't expose a node under /dev/, but the sensor >> exposes it. Probably because it uses V4L2_SUBDEV_FL_HAS_DEVNODE and sun6i-csi() calls >> v4l2_device_register_subdev_nodes(). >> >> I find this weird from a userspace pov, since usually we don't mix manual and auto propagation >> of the configs, so I started wondering if sun6i-csi driver should be calling >> v4l2_device_register_subdev_nodes() in the first place. > > I must admit that I didn't really pay attention to that, but since > sun6i-mipi-csi2 is basically a bridge driver, it doesn't make sense to apply > manual configuration to it. It is actually designed to forward most subdev ops > to its own subdev so configuring it manually would actually result in > configuring the sensor. Ack, then maybe sun6i-csi needs a patch removing the call to v4l2_device_register_subdev_nodes() > > XXX > >> Also, sun6i-csi doesn't seem to be used by any board dts (it's declared on the dtsi, but I >> didn't find any dts enabling it), so I wonder if it would be a bad thing if we update it. >> >>> pad0: Source >>> [fmt:SBGGR8_1X8/640x480 at 1/30 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range] >>> -> "sun6i-mipi-csi2":0 [ENABLED,IMMUTABLE] >> >> If I understand correctly, this is very similar to ipu3: >> sensor->bus->dma_engine >> >> in the case of ipu3-cio2: >> sensor->ipu3-csi2->ipu3-cio2 >> >> in this case: >> ov5648->sun6i-mipi-csi2->sun6i-csi > > Yes this is the correct picture. > >> On thing that is confusing me is the name csi2 with csi (that makes me think of csi >> version one, which is not the case), I would rename it to sun6i-video (or maybe >> it is just me who gets confused). > > So the CSI name comes from the Allwinner litterature and implementation for that > controller. Since it supports parallel input on its own, it does in fact support > parallel CSI. The DMA engine part alone from that controller is also used for > MIPI CSI-2, so in this case the name looses its relevance. > >> I know this driver is already upstream and not part of this series, but on the other hand it >> doesn't seem to be used. > > Personally I don't find a rename to be necessary and while I agree that > nothing would apparently prevent us from renaming it, I would prefer to keep > the naming in line with Allwinner's litterature. Ok, I didn't know it was from Allwinner's litterature, I don't mind keeping the name. > >> On another note, I always wonder if we should expose the bus in the topology, I'm not >> sure if it provides any useful API or information for userspace, and you could have >> a cleaner code (maybe code could be under phy subsystem). But at the same time, it >> seems this is a pattern on v4l2. >> >> I'd like to hear what others think on the above. > > My view on this is that we are dealing with two distinct controllers here, > one that acts as a DMA engine and one that acts as a bridge. As a result, two > chained subdevs looks like the most appropriate representation to me. > > Using the PHY subsystem would probably be abusing the framework since the > MIPI CSI-2 controller is not a PHY (and we do have a D-PHY driver for the D-PHY > part that uses the PHY API already). > > So tl;dr I don't agree that it would be cleaner. My point is, this is a "dummy" subdevice in userspace pov, but if it is only used with auto-propagation of the configurations, then it doesn't matter (since userspace won't interact with that node). And in the kernel space you need to implement media boilerplate code. So I was trying to think in another alternative, but tbh I don't mind keeping it in the media topology. Regards, Helen > > Cheers, > > Paul > >>> Happy reviewing! >>> >>> Paul Kocialkowski (14): >>> phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes >>> phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI >>> CSI-2 >>> media: sun6i-csi: Support an optional dedicated memory pool >>> media: sun6i-csi: Fix the image storage bpp for 10/12-bit Bayer >>> formats >>> media: sun6i-csi: Only configure the interface data width for parallel >>> media: sun6i-csi: Support feeding from the MIPI CSI-2 controller >>> dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation >>> media: sunxi: Add support for the A31 MIPI CSI-2 controller >>> ARM: dts: sun8i: v3s: Add CSI0 camera interface node >>> ARM: dts: sun8i: v3s: Add MIPI D-PHY and MIPI CSI-2 interface nodes >>> dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation >>> media: sunxi: Add support for the A83T MIPI CSI-2 controller >>> ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node >>> media: sunxi: sun8i-a83t-mipi-csi2: Avoid using the (unsolicited) >>> interrupt >>> >>> .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 +++++ >>> .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 +++++ >>> arch/arm/boot/dts/sun8i-a83t.dtsi | 26 + >>> arch/arm/boot/dts/sun8i-v3s.dtsi | 62 ++ >>> drivers/media/platform/sunxi/Kconfig | 2 + >>> drivers/media/platform/sunxi/Makefile | 2 + >>> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 54 +- >>> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 20 +- >>> .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + >>> .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + >>> .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 +++++++++++++++++ >>> .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 +++ >>> .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + >>> .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + >>> .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ >>> .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ >>> .../sun8i_a83t_mipi_csi2.c | 660 ++++++++++++++++++ >>> .../sun8i_a83t_mipi_csi2.h | 196 ++++++ >>> drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 ++++- >>> drivers/staging/media/rkisp1/rkisp1-isp.c | 3 +- >>> include/linux/phy/phy-mipi-dphy.h | 13 + >>> 21 files changed, 2408 insertions(+), 32 deletions(-) >>> create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml >>> create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h >>> > From helen.koike at collabora.com Wed Nov 4 16:38:08 2020 From: helen.koike at collabora.com (Helen Koike) Date: Wed, 4 Nov 2020 13:38:08 -0300 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201104111710.GB287014@aptenodytes> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> <20201102092110.ro6a456lvbrktwoz@gilmour.lan> <20201104111710.GB287014@aptenodytes> Message-ID: On 11/4/20 8:17 AM, Paul Kocialkowski wrote: > Hi, > > On Mon 02 Nov 20, 10:21, Maxime Ripard wrote: >> On Fri, Oct 30, 2020 at 07:45:18PM -0300, Helen Koike wrote: >>> On 10/23/20 2:45 PM, Paul Kocialkowski wrote: >>>> The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller >>>> found on Allwinner SoCs such as the A31 and V3/V3s. >>>> >>>> It is a standalone block, connected to the CSI controller on one side >>>> and to the MIPI D-PHY block on the other. It has a dedicated address >>>> space, interrupt line and clock. >>>> >>>> Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI >>>> controller (CSI0) but newer SoCs (such as the V5) may allow switching >>>> MIPI CSI-2 controllers between CSI controllers. >>>> >>>> It is represented as a V4L2 subdev to the CSI controller and takes a >>>> MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and >>>> media controller API. >>> >>> Maybe this is a bad idea, but I was thinking: >>> This driver basically just turn on/off and catch some interrupts for errors, >>> and all the rest of v4l2 config you just forward to the next subdevice >>> on the pipeline. >>> >>> So instead of exposing it as a subdevice, I was wondering if modeling >>> this driver also through the phy subsystem wouldn't be cleaner, so >>> you won't need all the v4l2 subdevice/topology boilerplate code that >>> it seems you are not using (unless you have plans to add controls or >>> some specific configuration on this node later). >>> >>> But this would require changes on the sun6i-csi driver. >>> >>> What do you think? >> >> Eventually we'll need to filter the virtual channels / datatypes I >> guess, so it's definitely valuable to have it in v4l2 Which kind of datatypes? I ask to know if this shouldn't be configured through the video node instead of subdevice. Regarding channels, we had a discussion to implement it through the video node (and not subdevice) [1]. But we discussed about blitters and multi-scalers, so now I'm wondering if we could use the same API for mipi-csi virtual channels in the video entity device, or if it doesn't apply and we need another API for that in a subdevice instead. [1] https://patchwork.linuxtv.org/project/linux-media/cover/20200717115435.2632623-1-helen.koike at collabora.com/ > > Agreed and like I mentionned in the discussion on 00/14 I don't think it > would be a cleaner way to expose things. > > There's also the fact that newer SoCs like the V5 seem to allow connecting > any MIPI CSI-2 controller to any CSI controller, so the graph representation > is definitely welcome here. I'm not sure this is an advantage in userspace pov, because it means we'll have different topologies for basically the same end result to userspace. But as I mentioned, I don't mind keeping it in the media topology. Helen > > Paul > From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:44 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:44 +0530 Subject: [PATCH v7 4/7] clk: clock-wizard: Add support for dynamic reconfiguration In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-5-git-send-email-shubhrajyoti.datta@xilinx.com> The patch adds support for dynamic reconfiguration of clock output rate. Output clocks are registered as dividers and set rate callback function is used for dynamic reconfiguration. Based on the initial work from Chirag. Signed-off-by: Chirag Parekh Signed-off-by: Shubhrajyoti Datta --- v6: Remove the typecast. use min for capping frequency. use polled timeout v7: Use devm functions Add the spinlock drivers/clk/clk-xlnx-clock-wizard.c | 181 ++++++++++++++++++++++++++++++++++-- 1 file changed, 175 insertions(+), 6 deletions(-) diff --git a/drivers/clk/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c index fb2d555..5581b24 100644 --- a/drivers/clk/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -17,6 +17,7 @@ #include #include #include +#include #define WZRD_NUM_OUTPUTS 7 #define WZRD_ACLK_MAX_FREQ 250000000UL @@ -31,8 +32,23 @@ #define WZRD_DIVCLK_DIVIDE_SHIFT 0 #define WZRD_DIVCLK_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) #define WZRD_CLKOUT_DIVIDE_SHIFT 0 +#define WZRD_CLKOUT_DIVIDE_WIDTH 8 #define WZRD_CLKOUT_DIVIDE_MASK (0xff << WZRD_DIVCLK_DIVIDE_SHIFT) +#define WZRD_DR_MAX_INT_DIV_VALUE 255 +#define WZRD_DR_NUM_RETRIES 10000 +#define WZRD_DR_STATUS_REG_OFFSET 0x04 +#define WZRD_DR_LOCK_BIT_MASK 0x00000001 +#define WZRD_DR_INIT_REG_OFFSET 0x25C +#define WZRD_DR_DIV_TO_PHASE_OFFSET 4 +#define WZRD_DR_BEGIN_DYNA_RECONF 0x03 + +/* Get the mask from width */ +#define div_mask(width) ((1 << (width)) - 1) + +/* Extract divider instance from clock hardware instance */ +#define to_clk_wzrd_divider(_hw) container_of(_hw, struct clk_wzrd_divider, hw) + enum clk_wzrd_int_clks { wzrd_clk_mul, wzrd_clk_mul_div, @@ -64,6 +80,29 @@ struct clk_wzrd { bool suspended; }; +/** + * struct clk_wzrd_divider - clock divider specific to clk_wzrd + * + * @hw: handle between common and hardware-specific interfaces + * @base: base address of register containing the divider + * @offset: offset address of register containing the divider + * @shift: shift to the divider bit field + * @width: width of the divider bit field + * @flags: clk_wzrd divider flags + * @table: array of value/divider pairs, last entry should have div = 0 + * @lock: register lock + */ +struct clk_wzrd_divider { + struct clk_hw hw; + void __iomem *base; + u16 offset; + u8 shift; + u8 width; + u8 flags; + const struct clk_div_table *table; + spinlock_t *lock; /* divider lock */ +}; + #define to_clk_wzrd(_nb) container_of(_nb, struct clk_wzrd, nb) /* maximum frequencies for input/output clocks per speed grade */ @@ -73,6 +112,132 @@ static const unsigned long clk_wzrd_max_freq[] = { 1066000000UL }; +/* spin lock variable for clk_wzrd */ +static DEFINE_SPINLOCK(clkwzrd_lock); + +static unsigned long clk_wzrd_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + unsigned int val; + + val = readl(div_addr) >> divider->shift; + val &= div_mask(divider->width); + + return divider_recalc_rate(hw, parent_rate, val, divider->table, + divider->flags, divider->width); +} + +static int clk_wzrd_dynamic_reconfig(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + int err = 0; + u32 value; + unsigned long flags = 0; + struct clk_wzrd_divider *divider = to_clk_wzrd_divider(hw); + void __iomem *div_addr = divider->base + divider->offset; + + if (divider->lock) + spin_lock_irqsave(divider->lock, flags); + else + __acquire(divider->lock); + + value = DIV_ROUND_CLOSEST(parent_rate, rate); + + /* Cap the value to max */ + min_t(u32, value, WZRD_DR_MAX_INT_DIV_VALUE); + + /* Set divisor and clear phase offset */ + writel(value, div_addr); + writel(0x00, div_addr + WZRD_DR_DIV_TO_PHASE_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); + if (err) + goto err_reconfig; + + /* Initiate reconfiguration */ + writel(WZRD_DR_BEGIN_DYNA_RECONF, + divider->base + WZRD_DR_INIT_REG_OFFSET); + + /* Check status register */ + err = readl_poll_timeout(divider->base + WZRD_DR_STATUS_REG_OFFSET, + value, value & WZRD_DR_LOCK_BIT_MASK, + WZRD_USEC_POLL, WZRD_TIMEOUT_POLL); +err_reconfig: + if (divider->lock) + spin_unlock_irqrestore(divider->lock, flags); + else + __release(divider->lock); + return err; +} + +static long clk_wzrd_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + u8 div; + + /* + * since we don't change parent rate we just round rate to closest + * achievable + */ + div = DIV_ROUND_CLOSEST(*prate, rate); + + return (*prate / div); +} + +static const struct clk_ops clk_wzrd_clk_divider_ops = { + .round_rate = clk_wzrd_round_rate, + .set_rate = clk_wzrd_dynamic_reconfig, + .recalc_rate = clk_wzrd_recalc_rate, +}; + +static struct clk *clk_wzrd_register_divider(struct device *dev, + const char *name, + const char *parent_name, + unsigned long flags, + void __iomem *base, u16 offset, + u8 shift, u8 width, + u8 clk_divider_flags, + const struct clk_div_table *table, + spinlock_t *lock) +{ + struct clk_wzrd_divider *div; + struct clk_hw *hw; + struct clk_init_data init; + int ret; + + div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL); + if (!div) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &clk_wzrd_clk_divider_ops; + init.flags = flags; + init.parent_names = &parent_name; + init.num_parents = 1; + + div->base = base; + div->offset = offset; + div->shift = shift; + div->width = width; + div->flags = clk_divider_flags; + div->lock = lock; + div->hw.init = &init; + div->table = table; + + /* register the clock */ + hw = &div->hw; + ret = devm_clk_hw_register(dev, hw); + if (ret) + hw = ERR_PTR(ret); + + return hw->clk; +} + static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event, void *data) { @@ -223,7 +388,8 @@ static int clk_wzrd_probe(struct platform_device *pdev) clk_wzrd->clks_internal[wzrd_clk_mul_div] = clk_register_fixed_factor (&pdev->dev, clk_name, __clk_get_name(clk_wzrd->clks_internal[wzrd_clk_mul]), - 0, 1, reg); + flags, ctrl_reg, 0, 8, CLK_DIVIDER_ONE_BASED | + CLK_DIVIDER_ALLOW_ZERO, &clkwzrd_lock); if (IS_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div])) { dev_err(&pdev->dev, "unable to register divider clock\n"); ret = PTR_ERR(clk_wzrd->clks_internal[wzrd_clk_mul_div]); @@ -241,11 +407,14 @@ static int clk_wzrd_probe(struct platform_device *pdev) ret = -EINVAL; goto err_rm_int_clks; } - reg = readl(clk_wzrd->base + WZRD_CLK_CFG_REG(2) + i * 12); - reg &= WZRD_CLKOUT_DIVIDE_MASK; - reg >>= WZRD_CLKOUT_DIVIDE_SHIFT; - clk_wzrd->clkout[i] = clk_register_fixed_factor - (&pdev->dev, clkout_name, clk_name, 0, 1, reg); + clk_wzrd->clkout[i] = clk_wzrd_register_divider(&pdev->dev, + clkout_name, + clk_name, 0, + clk_wzrd->base, (WZRD_CLK_CFG_REG(2) + i * 12), + WZRD_CLKOUT_DIVIDE_SHIFT, + WZRD_CLKOUT_DIVIDE_WIDTH, + CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, + NULL, &clkwzrd_lock); if (IS_ERR(clk_wzrd->clkout[i])) { int j; -- 2.1.1 From shubhrajyoti.datta at xilinx.com Wed Nov 4 15:06:43 2020 From: shubhrajyoti.datta at xilinx.com (Shubhrajyoti Datta) Date: Wed, 4 Nov 2020 20:36:43 +0530 Subject: [PATCH v7 3/7] clk: clock-wizard: Fix kernel-doc warning In-Reply-To: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <1604502407-14352-4-git-send-email-shubhrajyoti.datta@xilinx.com> Update description for the clocking wizard structure Signed-off-by: Shubhrajyoti Datta --- drivers/clk/clk-xlnx-clock-wizard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/clk/clk-xlnx-clock-wizard.c b/drivers/clk/clk-xlnx-clock-wizard.c index 1bab68e..fb2d555 100644 --- a/drivers/clk/clk-xlnx-clock-wizard.c +++ b/drivers/clk/clk-xlnx-clock-wizard.c @@ -40,7 +40,8 @@ enum clk_wzrd_int_clks { }; /** - * struct clk_wzrd: + * struct clk_wzrd - Clock wizard private data structure + * * @clk_data: Clock data * @nb: Notifier block * @base: Memory base -- 2.1.1 From maxime at cerno.tech Wed Nov 4 16:53:08 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Wed, 4 Nov 2020 17:53:08 +0100 Subject: [PATCH 07/14] dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation In-Reply-To: <20201104104827.GD285779@aptenodytes> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-8-paul.kocialkowski@bootlin.com> <20201026161450.gr3dqpltxw2ccc3s@gilmour.lan> <20201027095221.GE168350@aptenodytes> <20201027184459.eberpkr52kay3du6@gilmour.lan> <20201104104827.GD285779@aptenodytes> Message-ID: <20201104165308.rcdxvzyj3kbiyfan@gilmour.lan> On Wed, Nov 04, 2020 at 11:48:27AM +0100, Paul Kocialkowski wrote: > Hi, > > On Tue 27 Oct 20, 19:44, Maxime Ripard wrote: > > On Tue, Oct 27, 2020 at 10:52:21AM +0100, Paul Kocialkowski wrote: > > > Hi, > > > > > > On Mon 26 Oct 20, 17:14, Maxime Ripard wrote: > > > > i2c? :) > > > > > > Oops, good catch! > > > > > > > On Fri, Oct 23, 2020 at 07:45:39PM +0200, Paul Kocialkowski wrote: > > > > > This introduces YAML bindings documentation for the A31 MIPI CSI-2 > > > > > controller. > > > > > > > > > > Signed-off-by: Paul Kocialkowski > > > > > --- > > > > > .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 ++++++++++++++++++ > > > > > 1 file changed, 168 insertions(+) > > > > > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > > > > > > > diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > > new file mode 100644 > > > > > index 000000000000..9adc0bc27033 > > > > > --- /dev/null > > > > > +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > > > > > @@ -0,0 +1,168 @@ > > > > > +# SPDX-License-Identifier: GPL-2.0 > > > > > +%YAML 1.2 > > > > > +--- > > > > > +$id: http://devicetree.org/schemas/media/allwinner,sun6i-a31-mipi-csi2.yaml# > > > > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > > > > + > > > > > +title: Allwinner A31 MIPI CSI-2 Device Tree Bindings > > > > > + > > > > > +maintainers: > > > > > + - Paul Kocialkowski > > > > > + > > > > > +properties: > > > > > + compatible: > > > > > + oneOf: > > > > > + - const: allwinner,sun6i-a31-mipi-csi2 > > > > > + - items: > > > > > + - const: allwinner,sun8i-v3s-mipi-csi2 > > > > > + - const: allwinner,sun6i-a31-mipi-csi2 > > > > > + > > > > > + reg: > > > > > + maxItems: 1 > > > > > + > > > > > + interrupts: > > > > > + maxItems: 1 > > > > > + > > > > > + clocks: > > > > > + items: > > > > > + - description: Bus Clock > > > > > + - description: Module Clock > > > > > + > > > > > + clock-names: > > > > > + items: > > > > > + - const: bus > > > > > + - const: mod > > > > > + > > > > > + phys: > > > > > + items: > > > > > + - description: MIPI D-PHY > > > > > + > > > > > + phy-names: > > > > > + items: > > > > > + - const: dphy > > > > > + > > > > > + resets: > > > > > + maxItems: 1 > > > > > + > > > > > + # See ./video-interfaces.txt for details > > > > > + ports: > > > > > + type: object > > > > > + > > > > > + properties: > > > > > + port at 0: > > > > > + type: object > > > > > + description: Input port, connect to a MIPI CSI-2 sensor > > > > > + > > > > > + properties: > > > > > + reg: > > > > > + const: 0 > > > > > + > > > > > + endpoint: > > > > > + type: object > > > > > + > > > > > + properties: > > > > > + remote-endpoint: true > > > > > + > > > > > + bus-type: > > > > > + const: 4 > > > > > + > > > > > + clock-lanes: > > > > > + maxItems: 1 > > > > > + > > > > > + data-lanes: > > > > > + minItems: 1 > > > > > + maxItems: 4 > > > > > + > > > > > + required: > > > > > + - bus-type > > > > > + - data-lanes > > > > > + - remote-endpoint > > > > > + > > > > > + additionalProperties: false > > > > > + > > > > > + required: > > > > > + - endpoint > > > > > + > > > > > + additionalProperties: false > > > > > + > > > > > + port at 1: > > > > > + type: object > > > > > + description: Output port, connect to a CSI controller > > > > > + > > > > > + properties: > > > > > + reg: > > > > > + const: 1 > > > > > + > > > > > + endpoint: > > > > > + type: object > > > > > + > > > > > + properties: > > > > > + remote-endpoint: true > > > > > + > > > > > + bus-type: > > > > > + const: 4 > > > > > > > > That one seems a bit weird. If the input and output ports are using the > > > > same format, what is that "bridge" supposed to be doing? > > > > > > Fair enough. What this represents is the internal link (likely a FIFO) between > > > the two controllers. It is definitely not a MIPI CSI-2 bus but there's no > > > mbus type for an internal link (probably because it's not a bus after all). > > > > > > Note that on the CSI controller side, we need the bus-type to be set to 4 for it > > > to properly select the MIPI CSI-2 input. So it just felt more logical to have > > > the same on the other side of the endpoint. On the other hand, we can just > > > remove it on the MIPI CSI-2 controller side since it won't check it and have it > > > fallback to the unknown mbus type. > > > > > > But that would make the types inconsistent on the two sides of the link. > > > I don't think V4L2 will complain about it at the moment, but it would also make > > > sense that it does eventually. > > > > > > What do you think? > > > > There's still the same issue though, it doesn't make any sense that a > > bridge doesn't change the bus type. If it really did, we wouldn't need > > that in the first place. > > Yes I agreee. > > > What you want to check in your driver is whether the subdev you're > > connected to has a sink pad that uses MIPI-CSI > > I'm not really sure that's possible, but if it is it would indeed be the most > appropriate solution. If it's not, we still need to know that we need to feed > from MIPI CSI-2 so I don't see any other option than report MIPI CSI-2 on both > ends of MIPI CSI-2 controller. > > But there's still the question of what media bus type should be reported for > the CSI <-> MIPI CSI-2 link. I'm fine with unknown but we could also add a > generic internal bus type for this case. I guess both questions would need to be discussed more on the v4l2 side. Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From fazilyildiran at gmail.com Wed Nov 4 18:15:23 2020 From: fazilyildiran at gmail.com (Necip Fazil Yildiran) Date: Wed, 4 Nov 2020 21:15:23 +0300 Subject: [PATCH] staging: ralink-gdma: fix kconfig dependency bug for DMA_RALINK Message-ID: <20201104181522.43567-1-fazilyildiran@gmail.com> When DMA_RALINK is enabled and DMADEVICES is disabled, it results in the following Kbuild warnings: WARNING: unmet direct dependencies detected for DMA_ENGINE Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] WARNING: unmet direct dependencies detected for DMA_VIRTUAL_CHANNELS Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] The reason is that DMA_RALINK selects DMA_ENGINE and DMA_VIRTUAL_CHANNELS without depending on or selecting DMADEVICES while DMA_ENGINE and DMA_VIRTUAL_CHANNELS are subordinate to DMADEVICES. This can also fail building the kernel as demonstrated in a bug report. Honor the kconfig dependency to remove unmet direct dependency warnings and avoid any potential build failures. Link: https://bugzilla.kernel.org/show_bug.cgi?id=210055 Signed-off-by: Necip Fazil Yildiran --- drivers/staging/ralink-gdma/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/ralink-gdma/Kconfig b/drivers/staging/ralink-gdma/Kconfig index 54e8029e6b1a..0017376234e2 100644 --- a/drivers/staging/ralink-gdma/Kconfig +++ b/drivers/staging/ralink-gdma/Kconfig @@ -2,6 +2,7 @@ config DMA_RALINK tristate "RALINK DMA support" depends on RALINK && !SOC_RT288X + depends on DMADEVICES select DMA_ENGINE select DMA_VIRTUAL_CHANNELS -- 2.25.1 From maxime at cerno.tech Wed Nov 4 18:45:38 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Wed, 4 Nov 2020 19:45:38 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> <20201102092110.ro6a456lvbrktwoz@gilmour.lan> <20201104111710.GB287014@aptenodytes> Message-ID: <20201104184538.f6qagsmjdoijbzmv@gilmour.lan> On Wed, Nov 04, 2020 at 01:38:08PM -0300, Helen Koike wrote: > > > On 11/4/20 8:17 AM, Paul Kocialkowski wrote: > > Hi, > > > > On Mon 02 Nov 20, 10:21, Maxime Ripard wrote: > >> On Fri, Oct 30, 2020 at 07:45:18PM -0300, Helen Koike wrote: > >>> On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > >>>> The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > >>>> found on Allwinner SoCs such as the A31 and V3/V3s. > >>>> > >>>> It is a standalone block, connected to the CSI controller on one side > >>>> and to the MIPI D-PHY block on the other. It has a dedicated address > >>>> space, interrupt line and clock. > >>>> > >>>> Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > >>>> controller (CSI0) but newer SoCs (such as the V5) may allow switching > >>>> MIPI CSI-2 controllers between CSI controllers. > >>>> > >>>> It is represented as a V4L2 subdev to the CSI controller and takes a > >>>> MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > >>>> media controller API. > >>> > >>> Maybe this is a bad idea, but I was thinking: > >>> This driver basically just turn on/off and catch some interrupts for errors, > >>> and all the rest of v4l2 config you just forward to the next subdevice > >>> on the pipeline. > >>> > >>> So instead of exposing it as a subdevice, I was wondering if modeling > >>> this driver also through the phy subsystem wouldn't be cleaner, so > >>> you won't need all the v4l2 subdevice/topology boilerplate code that > >>> it seems you are not using (unless you have plans to add controls or > >>> some specific configuration on this node later). > >>> > >>> But this would require changes on the sun6i-csi driver. > >>> > >>> What do you think? > >> > >> Eventually we'll need to filter the virtual channels / datatypes I > >> guess, so it's definitely valuable to have it in v4l2 > > Which kind of datatypes? MIPI-CSI datatypes. Each packet on the MIPI-CSI bus is assigned a virtual channel and data type so that you can multiplex multiple streams (like a 3d camera would send for example, through the virtual channels) and data types (like frames and metadata) and MIPI-CSI controllers usually allow to filter them based on what you want. > I ask to know if this shouldn't be configured through the video node > instead of subdevice. Not really, some setups have a mux that can split the multiple virtual channels to multiple video nodes for example. > Regarding channels, we had a discussion to implement it through the video > node (and not subdevice) [1]. But we discussed about blitters and multi-scalers, > so now I'm wondering if we could use the same API for mipi-csi virtual channels > in the video entity device, or if it doesn't apply and we need another API > for that in a subdevice instead. > > [1] https://patchwork.linuxtv.org/project/linux-media/cover/20200717115435.2632623-1-helen.koike at collabora.com/ There's already an API to deal with MIPI-CSI virtual channels: https://patchwork.kernel.org/project/linux-renesas-soc/cover/20190328200608.9463-1-jacopo+renesas at jmondi.org/ Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From maxime at cerno.tech Wed Nov 4 18:56:50 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Wed, 4 Nov 2020 19:56:50 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201104113458.GC287014@aptenodytes> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <20201026165407.rrq6ccsexcsub5bm@gilmour.lan> <20201104113458.GC287014@aptenodytes> Message-ID: <20201104185650.ii7dlekjtfar2xpp@gilmour.lan> On Wed, Nov 04, 2020 at 12:34:58PM +0100, Paul Kocialkowski wrote: > > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, > > > + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | > > > + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); > > > > It's not really clear what the channel is here? The number of virtual > > channels? Something else? > > That's somewhat described in the controller documentation. Channels refers to > physical channels of the controller, which can be used to redirect data > matching either a specific data type, a specific virtual channel, or both. > There's a somewhat similar concept of channels in the CSI controller too. > > We're currently only using one... > > > > + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); > > ... but it's safer to configure them all to virtual channel numbers so we don't > end up with multiple channels matching virtual channel 0. > > I'll add a comment about that. Maybe we should have pads for all of them then, even if we don't support changing anything? > > > +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { > > > + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, > > > + .get_fmt = sun6i_mipi_csi2_get_fmt, > > > + .set_fmt = sun6i_mipi_csi2_set_fmt, > > > + .enum_frame_size = sun6i_mipi_csi2_enum_frame_size, > > > + .enum_frame_interval = sun6i_mipi_csi2_enum_frame_interval, > > > +}; > > > + > > > +/* Subdev */ > > > + > > > +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { > > > + .core = &sun6i_mipi_csi2_subdev_core_ops, > > > + .video = &sun6i_mipi_csi2_subdev_video_ops, > > > + .pad = &sun6i_mipi_csi2_subdev_pad_ops, > > > +}; > > > + > > > +/* Notifier */ > > > + > > > +static int sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, > > > + struct v4l2_subdev *remote_subdev, > > > + struct v4l2_async_subdev *remote_subdev_async) > > > +{ > > > + struct v4l2_subdev *subdev = notifier->sd; > > > + struct sun6i_mipi_csi2_video *video = > > > + sun6i_mipi_csi2_subdev_video(subdev); > > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > > + int source_pad; > > > + int ret; > > > + > > > + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, > > > + remote_subdev->fwnode, > > > + MEDIA_PAD_FL_SOURCE); > > > + if (source_pad < 0) > > > + return source_pad; > > > + > > > + ret = media_create_pad_link(&remote_subdev->entity, source_pad, > > > + &subdev->entity, 0, > > > + MEDIA_LNK_FL_ENABLED | > > > + MEDIA_LNK_FL_IMMUTABLE); > > > + if (ret) { > > > + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", > > > + remote_subdev->entity.name, source_pad, > > > + subdev->entity.name, 0); > > > + return ret; > > > + } > > > + > > > + video->remote_subdev = remote_subdev; > > > + video->remote_pad_index = source_pad; > > > + > > > + return 0; > > > +} > > > + > > > +static const struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { > > > + .bound = sun6i_mipi_csi2_notifier_bound, > > > +}; > > > + > > > +/* Media Entity */ > > > + > > > +static int sun6i_mipi_csi2_link_validate(struct media_link *link) > > > +{ > > > + struct v4l2_subdev *subdev = > > > + container_of(link->sink->entity, struct v4l2_subdev, entity); > > > + struct sun6i_mipi_csi2_video *video = > > > + sun6i_mipi_csi2_subdev_video(subdev); > > > + struct v4l2_subdev *remote_subdev; > > > + struct v4l2_subdev_format format = { 0 }; > > > + int ret; > > > + > > > + if (!is_media_entity_v4l2_subdev(link->source->entity)) > > > + return -EINVAL; > > > + > > > + remote_subdev = media_entity_to_v4l2_subdev(link->source->entity); > > > + > > > + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; > > > + format.pad = link->source->index; > > > + > > > + ret = v4l2_subdev_call(remote_subdev, pad, get_fmt, NULL, &format); > > > + if (ret) > > > + return ret; > > > + > > > + video->mbus_code = format.format.code; > > > + > > > + return 0; > > > +} > > > > I'm not really sure what you're trying to validate here? > > The whole purpose is to retreive video->mbus_code from the subdev, like it's > done in the sun6i-csi driver. Maybe there is a more appropriate op to do it? I'm not sure why you need to do that in the link_validate though? You just need to init the pad format, and then you'll have a get_fmt/set_fmt for your pads. > > > + cdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, > > > + &sun6i_mipi_csi2_regmap_config); > > > + if (IS_ERR(cdev->regmap)) { > > > + dev_err(&pdev->dev, "failed to init register map\n"); > > > + return PTR_ERR(cdev->regmap); > > > + } > > > > Yeah, so that won't work. regmap expects to have access to those > > registers when you enable that clock, but that won't happen since the > > reset line can be disabled. You would be better off using runtime_pm > > here. > > I don't understand what you mean here or what the problem could be. > Here we're just initializing regmap and while this is done before the > registers are available for I/O, I don't see why it would cause any > issue at this point. The regmap here is supposed to take care of the resources, except it only does it for some of the resources here, which kind of breaks the expectations. And it doesn't allow you to have the reset / clock sequence properly done. > The exact same thing is done in the CSI driver. That's not an argument though, is it? :) Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From robh at kernel.org Wed Nov 4 19:06:12 2020 From: robh at kernel.org (Rob Herring) Date: Wed, 4 Nov 2020 13:06:12 -0600 Subject: [PATCH v3 09/11] dt-bindings: pwm: Add binding for RPi firmware PWM bus In-Reply-To: <20201104103938.1286-10-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-10-nsaenzjulienne@suse.de> Message-ID: <20201104190612.GA3959462@bogus> On Wed, 04 Nov 2020 11:39:35 +0100, Nicolas Saenz Julienne wrote: > The PWM bus controlling the fan in RPi's official PoE hat can only be > controlled by the board's co-processor. > > Signed-off-by: Nicolas Saenz Julienne > Reviewed-by: Rob Herring > > --- > > Changes since v1: > - Update bindings to use 2 #pwm-cells > > .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 +++++++++++++++++++ > .../pwm/raspberrypi,firmware-pwm.h | 13 ++++++++++++ > 2 files changed, 33 insertions(+) > create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.example.dt.yaml: firmware: pwm:#pwm-cells:0:0: 2 was expected From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml See https://patchwork.ozlabs.org/patch/1393804 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From robh at kernel.org Wed Nov 4 19:11:46 2020 From: robh at kernel.org (Rob Herring) Date: Wed, 4 Nov 2020 13:11:46 -0600 Subject: [PATCH v7 1/7] dt-bindings: add documentation of xilinx clocking wizard In-Reply-To: <1604502407-14352-2-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> <1604502407-14352-2-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <20201104191146.GA3967018@bogus> On Wed, 04 Nov 2020 20:36:41 +0530, Shubhrajyoti Datta wrote: > Add the devicetree binding for the xilinx clocking wizard. > > Signed-off-by: Shubhrajyoti Datta > --- > v6: > Fix a yaml warning > v7: > Add vendor prefix speed-grade > > .../bindings/clock/xlnx,clocking-wizard.yaml | 65 ++++++++++++++++++++++ > 1 file changed, 65 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: ./Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml:21:7: [warning] wrong indentation: expected 4 but found 6 (indentation) ./Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml:38:7: [warning] wrong indentation: expected 4 but found 6 (indentation) ./Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml:40:5: [error] syntax error: expected , but found '' (syntax) dtschema/dtc warnings/errors: Traceback (most recent call last): File "/usr/local/bin/dt-extract-example", line 45, in binding = yaml.load(open(args.yamlfile, encoding='utf-8').read()) File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/main.py", line 343, in load return constructor.get_single_data() File "/usr/local/lib/python3.8/dist-packages/ruamel/yaml/constructor.py", line 111, in get_single_data node = self.composer.get_single_node() File "_ruamel_yaml.pyx", line 706, in _ruamel_yaml.CParser.get_single_node File "_ruamel_yaml.pyx", line 724, in _ruamel_yaml.CParser._compose_document File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node File "_ruamel_yaml.pyx", line 889, in _ruamel_yaml.CParser._compose_mapping_node File "_ruamel_yaml.pyx", line 775, in _ruamel_yaml.CParser._compose_node File "_ruamel_yaml.pyx", line 891, in _ruamel_yaml.CParser._compose_mapping_node File "_ruamel_yaml.pyx", line 904, in _ruamel_yaml.CParser._parse_next_event ruamel.yaml.parser.ParserError: while parsing a block mapping in "", line 20, column 3 did not find expected key in "", line 40, column 5 make[1]: *** [Documentation/devicetree/bindings/Makefile:20: Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.example.dts] Error 1 make[1]: *** Deleting file 'Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.example.dts' make[1]: *** Waiting for unfinished jobs.... make[1]: *** [Documentation/devicetree/bindings/Makefile:59: Documentation/devicetree/bindings/processed-schema-examples.json] Error 123 make: *** [Makefile:1364: dt_binding_check] Error 2 See https://patchwork.ozlabs.org/patch/1394053 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From robh at kernel.org Wed Nov 4 19:15:20 2020 From: robh at kernel.org (Rob Herring) Date: Wed, 4 Nov 2020 13:15:20 -0600 Subject: [PATCH v7 1/7] dt-bindings: add documentation of xilinx clocking wizard In-Reply-To: <1604502407-14352-2-git-send-email-shubhrajyoti.datta@xilinx.com> References: <1604502407-14352-1-git-send-email-shubhrajyoti.datta@xilinx.com> <1604502407-14352-2-git-send-email-shubhrajyoti.datta@xilinx.com> Message-ID: <20201104191520.GB3967018@bogus> On Wed, Nov 04, 2020 at 08:36:41PM +0530, Shubhrajyoti Datta wrote: > Add the devicetree binding for the xilinx clocking wizard. > > Signed-off-by: Shubhrajyoti Datta > --- > v6: > Fix a yaml warning > v7: > Add vendor prefix speed-grade > > .../bindings/clock/xlnx,clocking-wizard.yaml | 65 ++++++++++++++++++++++ > 1 file changed, 65 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml > > diff --git a/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml > new file mode 100644 > index 0000000..a19b9bb > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/xlnx,clocking-wizard.yaml > @@ -0,0 +1,65 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/clock/xlnx,clocking-wizard.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Xilinx clocking wizard > + > +maintainers: > + - Shubhrajyoti Datta > + > +description: | > + The clocking wizard is a soft ip clocking block of Xilinx versal. It > + reads required input clock frequencies from the devicetree and acts as clock > + clock output. > + > +select: false Why? That's one way to make the example pass with your schema... > + > +properties: > + compatible: > + - enum: > + - xlnx,clocking-wizard > + > + "#clock-cells": > + const: 1 > + > + clocks: > + items: > + - description: clock input > + - description: axi clock > + > + clock-names: > + items: > + - const: clk_in1 > + - const: s_axi_aclk > + > + xlnx,speed-grade: > + - $ref: /schemas/types.yaml#/definitions/uint32 > + - enum: [1, 2, 3] > + description: > + Speed grade of the device. > + > +required: > + - compatible > + - "#clock-cells" > + - clocks > + - clock-names > + - speed-grade > + > +additionalProperties: false > + > +examples: > + - | > + clock-generator at 40040000 { > + #clock-cells = <1>; > + reg = <0x40040000 0x1000>; > + compatible = "xlnx,clocking-wizard"; > + xlnx,speed-grade = <1>; > + clock-names = "clk_in1", "s_axi_aclk"; > + clocks = <&clkc 15>, <&clkc 15>; > + clock-output-names = "clk_out1", "clk_out2", > + "clk_out3", "clk_out4", "clk_out5", > + "clk_out6", "clk_out7"; > + }; > +... > -- > 2.1.1 > From robh at kernel.org Wed Nov 4 19:15:54 2020 From: robh at kernel.org (Rob Herring) Date: Wed, 4 Nov 2020 13:15:54 -0600 Subject: [PATCH v3 02/24] dt-bindings: introduce silabs,wfx.yaml In-Reply-To: <20201104155207.128076-3-Jerome.Pouiller@silabs.com> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> <20201104155207.128076-3-Jerome.Pouiller@silabs.com> Message-ID: <20201104191554.GA3972736@bogus> On Wed, 04 Nov 2020 16:51:45 +0100, Jerome Pouiller wrote: > From: J?r?me Pouiller > > Signed-off-by: J?r?me Pouiller > --- > .../bindings/net/wireless/silabs,wfx.yaml | 131 ++++++++++++++++++ > 1 file changed, 131 insertions(+) > create mode 100644 Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml: 'additionalProperties' is a required property /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml: ignoring, error in schema: warning: no schema found in file: ./Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml See https://patchwork.ozlabs.org/patch/1394182 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From wtertwetwetwet at mail.ru Wed Nov 4 10:58:09 2020 From: wtertwetwetwet at mail.ru (wtertwetwetwet at mail.ru) Date: Wed, 4 Nov 2020 10:58:09 +0000 (UTC) Subject: Zdravstvujte! Vas interesujut bazy dannyh? Message-ID: <20201104105809.C001383E2@pserver06.localdomain> Zdravstvujte! Vas interesujut bazy dannyh? From nsaenzjulienne at suse.de Wed Nov 4 19:55:19 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Wed, 04 Nov 2020 20:55:19 +0100 Subject: [PATCH v3 09/11] dt-bindings: pwm: Add binding for RPi firmware PWM bus In-Reply-To: <20201104190612.GA3959462@bogus> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-10-nsaenzjulienne@suse.de> <20201104190612.GA3959462@bogus> Message-ID: <4debc77f5c72e1f4eff36a700231493bf9fbf404.camel@suse.de> On Wed, 2020-11-04 at 13:06 -0600, Rob Herring wrote: > On Wed, 04 Nov 2020 11:39:35 +0100, Nicolas Saenz Julienne wrote: > > The PWM bus controlling the fan in RPi's official PoE hat can only be > > controlled by the board's co-processor. > > > > Signed-off-by: Nicolas Saenz Julienne > > Reviewed-by: Rob Herring > > > > --- > > > > Changes since v1: > > - Update bindings to use 2 #pwm-cells > > > > .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 +++++++++++++++++++ > > .../pwm/raspberrypi,firmware-pwm.h | 13 ++++++++++++ > > 2 files changed, 33 insertions(+) > > create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h > > > > My bot found errors running 'make dt_binding_check' on your patch: > > yamllint warnings/errors: > > dtschema/dtc warnings/errors: > /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.example.dt.yaml: firmware: pwm:#pwm-cells:0:0: 2 was expected Yes I forgot to update the example... Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From Markus.Elfring at web.de Wed Nov 4 20:50:43 2020 From: Markus.Elfring at web.de (Markus Elfring) Date: Wed, 4 Nov 2020 21:50:43 +0100 Subject: [v2] media: atomisp: Fix error handling path In-Reply-To: <20201104114015.GH18329@kadam> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> <65712450-1ee9-2dd3-cd43-f850807ae203@web.de> <20201104083121.GG18329@kadam> <85ff17ad-8aa7-a457-6e23-4f5c1c5152f2@web.de> <20201104114015.GH18329@kadam> Message-ID: <4fac89cb-0420-8211-6f10-f03f78588744@web.de> >> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?id=4ef8451b332662d004df269d4cdeb7d9f31419b5#n123 > > The documentation is correct but no one wants you to constantly be > nagging developers about minor stuff... Would you interpret patch review attempts in any other directions? Regards, Markus From robh at kernel.org Wed Nov 4 22:30:42 2020 From: robh at kernel.org (Rob Herring) Date: Wed, 4 Nov 2020 16:30:42 -0600 Subject: [PATCH v4 1/4] dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY In-Reply-To: <20201031122246.16497-2-sergio.paracuellos@gmail.com> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-2-sergio.paracuellos@gmail.com> Message-ID: <20201104223042.GA43042@bogus> On Sat, 31 Oct 2020 13:22:43 +0100, Sergio Paracuellos wrote: > Add bindings to describe Mediatek MT7621 PCIe PHY. > > Signed-off-by: Sergio Paracuellos > --- > .../bindings/phy/mediatek,mt7621-pci-phy.yaml | 36 +++++++++++++++++++ > 1 file changed, 36 insertions(+) > create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml > Reviewed-by: Rob Herring From lkp at intel.com Wed Nov 4 22:40:23 2020 From: lkp at intel.com (kernel test robot) Date: Thu, 05 Nov 2020 06:40:23 +0800 Subject: [driver-core:driver-core-linus] BUILD SUCCESS d181bfe36715a1834958cf2d62253b624adfae51 Message-ID: <5fa32dd7.wzQwenZYUaxYpgkv%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git driver-core-linus branch HEAD: d181bfe36715a1834958cf2d62253b624adfae51 Documentation: remove mic/index from misc-devices/index.rst elapsed time: 721m configs tested: 182 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig sh se7206_defconfig m68k bvme6000_defconfig m68k sun3_defconfig h8300 defconfig arm shmobile_defconfig sh se7751_defconfig arm vexpress_defconfig mips ath25_defconfig arm u300_defconfig arm efm32_defconfig arm davinci_all_defconfig riscv nommu_k210_defconfig sh alldefconfig arm prima2_defconfig powerpc fsp2_defconfig sh se7705_defconfig mips ip28_defconfig m68k m5208evb_defconfig sh se7712_defconfig arm multi_v7_defconfig sh rsk7269_defconfig sh secureedge5410_defconfig mips maltaup_defconfig arm pxa255-idp_defconfig arm tango4_defconfig powerpc motionpro_defconfig powerpc amigaone_defconfig sh se7724_defconfig s390 zfcpdump_defconfig powerpc mpc834x_itx_defconfig ia64 defconfig m68k m5249evb_defconfig arm pxa910_defconfig openrisc defconfig mips tb0226_defconfig xtensa defconfig mips malta_kvm_defconfig sh ecovec24-romimage_defconfig arm pcm027_defconfig arm mvebu_v5_defconfig powerpc sam440ep_defconfig mips db1xxx_defconfig arm pleb_defconfig arm mvebu_v7_defconfig sh sh7785lcr_defconfig arm spear3xx_defconfig powerpc cm5200_defconfig arc hsdk_defconfig mips jmr3927_defconfig powerpc ppc6xx_defconfig arm integrator_defconfig powerpc mpc837x_rdb_defconfig powerpc tqm8xx_defconfig mips cu1000-neo_defconfig mips xway_defconfig arm exynos_defconfig mips ath79_defconfig sh landisk_defconfig m68k amiga_defconfig arm mmp2_defconfig powerpc canyonlands_defconfig mips malta_qemu_32r6_defconfig powerpc tqm8555_defconfig arm ep93xx_defconfig i386 alldefconfig sh se7722_defconfig powerpc holly_defconfig mips bcm47xx_defconfig mips gpr_defconfig powerpc chrp32_defconfig mips decstation_64_defconfig ia64 gensparse_defconfig riscv rv32_defconfig powerpc kilauea_defconfig mips nlm_xlp_defconfig arm pxa_defconfig xtensa virt_defconfig powerpc allyesconfig c6x evmc6678_defconfig sh apsh4ad0a_defconfig mips ip22_defconfig mips tb0287_defconfig sh ap325rxa_defconfig powerpc stx_gp3_defconfig sh magicpanelr2_defconfig sh r7785rp_defconfig powerpc ppc64e_defconfig arm iop32x_defconfig m68k mac_defconfig sh edosk7760_defconfig powerpc taishan_defconfig riscv nommu_virt_defconfig powerpc katmai_defconfig sh sh7710voipgw_defconfig arm orion5x_defconfig mips rt305x_defconfig s390 debug_defconfig arm stm32_defconfig sh se7780_defconfig mips ar7_defconfig powerpc cell_defconfig sh sh7785lcr_32bit_defconfig powerpc iss476-smp_defconfig ia64 generic_defconfig arm mv78xx0_defconfig sh shmin_defconfig m68k multi_defconfig ia64 allmodconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a004-20201104 i386 randconfig-a006-20201104 i386 randconfig-a005-20201104 i386 randconfig-a001-20201104 i386 randconfig-a002-20201104 i386 randconfig-a003-20201104 i386 randconfig-a004-20201105 i386 randconfig-a006-20201105 i386 randconfig-a005-20201105 i386 randconfig-a001-20201105 i386 randconfig-a002-20201105 i386 randconfig-a003-20201105 x86_64 randconfig-a012-20201104 x86_64 randconfig-a015-20201104 x86_64 randconfig-a013-20201104 x86_64 randconfig-a011-20201104 x86_64 randconfig-a014-20201104 x86_64 randconfig-a016-20201104 i386 randconfig-a015-20201104 i386 randconfig-a013-20201104 i386 randconfig-a014-20201104 i386 randconfig-a016-20201104 i386 randconfig-a011-20201104 i386 randconfig-a012-20201104 riscv allyesconfig riscv allnoconfig riscv defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a004-20201104 x86_64 randconfig-a003-20201104 x86_64 randconfig-a005-20201104 x86_64 randconfig-a002-20201104 x86_64 randconfig-a006-20201104 x86_64 randconfig-a001-20201104 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From digetx at gmail.com Wed Nov 4 23:43:57 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:43:57 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs Message-ID: <20201104234427.26477-1-digetx@gmail.com> Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces power consumption and heating of the Tegra chips. Tegra SoC has multiple hardware units which belong to a core power domain of the SoC and share the core voltage. The voltage must be selected in accordance to a minimum requirement of every core hardware unit. The minimum core voltage requirement depends on: 1. Clock enable state of a hardware unit. 2. Clock frequency. 3. Unit's internal idling/active state. This series is tested on Acer A500 (T20), AC100 (T20), Nexus 7 (T30) and Ouya (T30) devices. I also added voltage scaling to the Ventana (T20) and Cardhu (T30) boards which are tested by NVIDIA's CI farm. Tegra30 is now up to 5C cooler on Nexus 7 and stays cool on Ouya (instead of becoming burning hot) while system is idling. It should be possible to improve this further by implementing a more advanced power management features for the kernel drivers. The DVFS support is opt-in for all boards, meaning that older DTBs will continue to work like they did it before this series. It should be possible to easily add the core voltage scaling support for Tegra114+ SoCs based on this grounding work later on, if anyone will want to implement it. WARNING(!) This series is made on top of the memory interconnect patches which are currently under review [1]. The Tegra EMC driver and devicetree-related patches need to be applied on top of the ICC series. [1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=212196 Dmitry Osipenko (30): dt-bindings: host1x: Document OPP and voltage regulator properties dt-bindings: mmc: tegra: Document OPP and voltage regulator properties dt-bindings: pwm: tegra: Document OPP and voltage regulator properties media: dt: bindings: tegra-vde: Document OPP and voltage regulator properties dt-binding: usb: ci-hdrc-usb2: Document OPP and voltage regulator properties dt-bindings: usb: tegra-ehci: Document OPP and voltage regulator properties soc/tegra: Add sync state API soc/tegra: regulators: Support Tegra SoC device sync state API soc/tegra: regulators: Fix lockup when voltage-spread is out of range regulator: Allow skipping disabled regulators in regulator_check_consumers() drm/tegra: dc: Support OPP and SoC core voltage scaling drm/tegra: gr2d: Correct swapped device-tree compatibles drm/tegra: gr2d: Support OPP and SoC core voltage scaling drm/tegra: gr3d: Support OPP and SoC core voltage scaling drm/tegra: hdmi: Support OPP and SoC core voltage scaling gpu: host1x: Support OPP and SoC core voltage scaling mmc: sdhci-tegra: Support OPP and core voltage scaling pwm: tegra: Support OPP and core voltage scaling media: staging: tegra-vde: Support OPP and SoC core voltage scaling usb: chipidea: tegra: Support OPP and SoC core voltage scaling usb: host: ehci-tegra: Support OPP and SoC core voltage scaling memory: tegra20-emc: Support Tegra SoC device state syncing memory: tegra30-emc: Support Tegra SoC device state syncing ARM: tegra: Add OPP tables for Tegra20 peripheral devices ARM: tegra: Add OPP tables for Tegra30 peripheral devices ARM: tegra: ventana: Add voltage supplies to DVFS-capable devices ARM: tegra: paz00: Add voltage supplies to DVFS-capable devices ARM: tegra: acer-a500: Add voltage supplies to DVFS-capable devices ARM: tegra: cardhu-a04: Add voltage supplies to DVFS-capable devices ARM: tegra: nexus7: Add voltage supplies to DVFS-capable devices .../display/tegra/nvidia,tegra20-host1x.txt | 56 +++ .../bindings/media/nvidia,tegra-vde.txt | 12 + .../bindings/mmc/nvidia,tegra20-sdhci.txt | 12 + .../bindings/pwm/nvidia,tegra20-pwm.txt | 13 + .../devicetree/bindings/usb/ci-hdrc-usb2.txt | 4 + .../bindings/usb/nvidia,tegra20-ehci.txt | 2 + .../boot/dts/tegra20-acer-a500-picasso.dts | 30 +- arch/arm/boot/dts/tegra20-paz00.dts | 40 +- .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 386 ++++++++++++++++ arch/arm/boot/dts/tegra20-ventana.dts | 65 ++- arch/arm/boot/dts/tegra20.dtsi | 14 + .../tegra30-asus-nexus7-grouper-common.dtsi | 23 + arch/arm/boot/dts/tegra30-cardhu-a04.dts | 44 ++ .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 415 ++++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 13 + drivers/gpu/drm/tegra/Kconfig | 1 + drivers/gpu/drm/tegra/dc.c | 138 +++++- drivers/gpu/drm/tegra/dc.h | 5 + drivers/gpu/drm/tegra/gr2d.c | 140 +++++- drivers/gpu/drm/tegra/gr3d.c | 136 ++++++ drivers/gpu/drm/tegra/hdmi.c | 63 ++- drivers/gpu/host1x/Kconfig | 1 + drivers/gpu/host1x/dev.c | 87 ++++ drivers/memory/tegra/tegra20-emc.c | 8 +- drivers/memory/tegra/tegra30-emc.c | 8 +- drivers/mmc/host/Kconfig | 1 + drivers/mmc/host/sdhci-tegra.c | 70 ++- drivers/pwm/Kconfig | 1 + drivers/pwm/pwm-tegra.c | 84 +++- drivers/regulator/core.c | 12 +- .../soc/samsung/exynos-regulator-coupler.c | 2 +- drivers/soc/tegra/common.c | 152 ++++++- drivers/soc/tegra/regulators-tegra20.c | 25 +- drivers/soc/tegra/regulators-tegra30.c | 30 +- drivers/staging/media/tegra-vde/Kconfig | 1 + drivers/staging/media/tegra-vde/vde.c | 127 ++++++ drivers/staging/media/tegra-vde/vde.h | 1 + drivers/usb/chipidea/Kconfig | 1 + drivers/usb/chipidea/ci_hdrc_tegra.c | 79 ++++ drivers/usb/host/Kconfig | 1 + drivers/usb/host/ehci-tegra.c | 79 ++++ include/linux/regulator/coupler.h | 6 +- include/soc/tegra/common.h | 22 + 43 files changed, 2360 insertions(+), 50 deletions(-) -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:43:58 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:43:58 +0300 Subject: [PATCH v1 01/30] dt-bindings: host1x: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-2-digetx@gmail.com> Document new DVFS OPP table and voltage regulator properties of the Host1x bus and devices sitting on the bus. Signed-off-by: Dmitry Osipenko --- .../display/tegra/nvidia,tegra20-host1x.txt | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt index 34d993338453..0593c8df70bb 100644 --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt @@ -20,6 +20,18 @@ Required properties: - reset-names: Must include the following entries: - host1x +Optional properties: +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- core-supply: Phandle of voltage regulator of the SoC "core" power domain. + +For each opp entry in 'operating-points-v2' table of host1x and its modules: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. + Each host1x client module having to perform DMA through the Memory Controller should have the interconnect endpoints set to the Memory Client and External Memory respectively. @@ -45,6 +57,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. + - operating-points-v2: See ../bindings/opp/opp.txt for details. - vi: video input @@ -128,6 +142,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - epp: encoder pre-processor @@ -147,6 +163,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - isp: image signal processor @@ -166,6 +184,7 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - gr2d: 2D graphics engine @@ -185,6 +204,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - gr3d: 3D graphics engine @@ -209,6 +230,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - dc: display controller @@ -241,6 +264,8 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - hdmi: High Definition Multimedia Interface @@ -267,6 +292,8 @@ of the following host1x client modules: - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection - nvidia,edid: supplies a binary EDID blob - nvidia,panel: phandle of a display panel + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - tvo: TV encoder output @@ -277,6 +304,10 @@ of the following host1x client modules: - clocks: Must contain one entry, for the module clock. See ../clocks/clock-bindings.txt for details. + Optional properties: + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. + - dsi: display serial interface Required properties: @@ -305,6 +336,8 @@ of the following host1x client modules: - nvidia,panel: phandle of a display panel - nvidia,ganged-mode: contains a phandle to a second DSI controller to gang up with in order to support up to 8 data lanes + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. - sor: serial output resource @@ -394,6 +427,7 @@ of the following host1x client modules: - interconnect-names: Must include name of the interconnect path for each interconnect entry. Consult TRM documentation for information about available memory clients, see MEMORY CONTROLLER section. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. Example: @@ -408,6 +442,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_HOST1X>; resets = <&tegra_car 28>; reset-names = "host1x"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; #address-cells = <1>; #size-cells = <1>; @@ -421,6 +457,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_MPE>; resets = <&tegra_car 60>; reset-names = "mpe"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; vi at 54080000 { @@ -429,6 +467,8 @@ Example: interrupts = ; assigned-clocks = <&tegra_car TEGRA210_CLK_VI>; assigned-clock-parents = <&tegra_car TEGRA210_CLK_PLL_C4_OUT0>; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; clocks = <&tegra_car TEGRA210_CLK_VI>; power-domains = <&pd_venc>; @@ -510,6 +550,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_EPP>; resets = <&tegra_car 19>; reset-names = "epp"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; isp { @@ -528,6 +570,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_GR2D>; resets = <&tegra_car 21>; reset-names = "2d"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; gr3d { @@ -536,6 +580,8 @@ Example: clocks = <&tegra_car TEGRA20_CLK_GR3D>; resets = <&tegra_car 24>; reset-names = "3d"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; dc at 54200000 { @@ -547,6 +593,8 @@ Example: clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; interconnects = <&mc TEGRA20_MC_DISPLAY0A &emc>, <&mc TEGRA20_MC_DISPLAY0B &emc>, @@ -571,6 +619,8 @@ Example: clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; interconnects = <&mc TEGRA20_MC_DISPLAY0AB &emc>, <&mc TEGRA20_MC_DISPLAY0BB &emc>, @@ -596,6 +646,8 @@ Example: resets = <&tegra_car 51>; reset-names = "hdmi"; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; tvo { @@ -604,6 +656,8 @@ Example: interrupts = <0 76 0x04>; clocks = <&tegra_car TEGRA20_CLK_TVO>; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; dsi { @@ -615,6 +669,8 @@ Example: resets = <&tegra_car 48>; reset-names = "dsi"; status = "disabled"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; }; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:43:59 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:43:59 +0300 Subject: [PATCH v1 02/30] dt-bindings: mmc: tegra: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-3-digetx@gmail.com> Document new DVFS OPP table and voltage regulator properties of the SDHCI controller. Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt index 96c0b1440c9c..1beb0416ae5f 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -31,6 +31,16 @@ Required properties: Optional properties: - power-gpios : Specify GPIOs for power control +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- core-supply: Phandle of voltage regulator of the SoC "core" power domain. + +For each opp entry in 'operating-points-v2' table: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. Example: @@ -45,6 +55,8 @@ sdhci at c8000200 { wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ bus-width = <8>; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; Optional properties for Tegra210, Tegra186 and Tegra194: -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:00 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:00 +0300 Subject: [PATCH v1 03/30] dt-bindings: pwm: tegra: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-4-digetx@gmail.com> Document new DVFS OPP table and voltage regulator properties of the PWM controller. Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index 74c41e34c3b6..d4d1c44a2c04 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -32,6 +32,17 @@ The PWM node will have following optional properties. pinctrl-names: Pin state names. Must be "default" and "sleep". pinctrl-0: phandle for the default/active state of pin configurations. pinctrl-1: phandle for the sleep state of pin configurations. +core-supply: phandle for voltage regulator of the SoC "core" power domain. + +operating-points-v2: see ../bindings/opp/opp.txt for details. + +For each opp entry in 'operating-points-v2' table: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. Example: @@ -42,6 +53,8 @@ Example: clocks = <&tegra_car 17>; resets = <&tegra_car 17>; reset-names = "pwm"; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:01 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:01 +0300 Subject: [PATCH v1 04/30] media: dt: bindings: tegra-vde: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-5-digetx@gmail.com> Document new DVFS OPP table and voltage regulator properties of the video decoder engine. Signed-off-by: Dmitry Osipenko --- .../devicetree/bindings/media/nvidia,tegra-vde.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt index 602169b8aa19..9854fa9d3cd3 100644 --- a/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt +++ b/Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt @@ -36,6 +36,16 @@ Optional properties: - reset-names : Must include the following entries: - mc - iommus: Must contain phandle to the IOMMU device node. +- operating-points-v2: See ../bindings/opp/opp.txt for details. +- core-supply: Phandle to voltage regulator of the SoC "core" power domain. + +For each opp entry in 'operating-points-v2' table: +- opp-supported-hw: One bitfield indicating: + On Tegra20: SoC process ID mask + On Tegra30+: SoC speedo ID mask + + A bitwise AND is performed against the value and if any bit + matches, the OPP gets enabled. Example: @@ -61,4 +71,6 @@ video-codec at 6001a000 { reset-names = "vde", "mc"; resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; iommus = <&mc TEGRA_SWGROUP_VDE>; + operating-points-v2 = <&dvfs_opp_table>; + core-supply = <&vdd_core>; }; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:02 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:02 +0300 Subject: [PATCH v1 05/30] dt-binding: usb: ci-hdrc-usb2: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-6-digetx@gmail.com> Document new OPP table and NVIDIA Tegra-specific voltage regulator properties. Signed-off-by: Dmitry Osipenko --- Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt index a5c5db6a0b2d..f02a98201062 100644 --- a/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt +++ b/Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt @@ -90,6 +90,7 @@ Optional properties: case, the "idle" state needs to pull down the data and strobe pin and the "active" state needs to pull up the strobe pin. - pinctrl-n: alternate pin modes +- operating-points-v2: See ../bindings/opp/opp.txt for details. i.mx specific properties - fsl,usbmisc: phandler of non-core register device, with one @@ -110,6 +111,9 @@ i.mx specific properties The range is from 0x0 to 0xf, the default value is 0x3. Details can refer to TXVREFTUNE0 bits of USBNC_n_PHY_CFG1. +Tegra specific properties +- core-supply: phandle of voltage regulator of the SoC "core" power domain + Example: usb at f7ed0000 { -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:03 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:03 +0300 Subject: [PATCH v1 06/30] dt-bindings: usb: tegra-ehci: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-7-digetx@gmail.com> Document new DVFS OPP table and voltage regulator properties of the Tegra EHCI controller. Signed-off-by: Dmitry Osipenko --- Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index f60785f73d3d..e4070ae21fd9 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -21,3 +21,5 @@ Required properties : Optional properties: - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 USB ports, which need reset twice due to hardware issues. + - operating-points-v2: See ../bindings/opp/opp.txt for details. + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:05 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:05 +0300 Subject: [PATCH v1 08/30] soc/tegra: regulators: Support Tegra SoC device sync state API In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-9-digetx@gmail.com> Downscale of the CORE voltage isn't allowed because some hardware units, which are supplied by the CORE regulator, usually left ON at a boot time. The new sync state API resolves this problem for us. All drivers of the devices that are known to be ON at a boot time now should sync theirs state. Once everything is synced, the voltage of the CORE domain could be scaled without any limitations. Make Tegra20/30 regulator couplers to use the new sync state API. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/regulators-tegra20.c | 19 ++++++++++++++++++- drivers/soc/tegra/regulators-tegra30.c | 22 +++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index 367a71a3cd10..8782e399a58c 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -16,6 +16,8 @@ #include #include +#include + struct tegra_regulator_coupler { struct regulator_coupler coupler; struct regulator_dev *core_rdev; @@ -38,6 +40,21 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra20 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Host1x bus for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_soc_dvfs_state_synced()) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -58,7 +75,7 @@ static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index 7f21f31de09d..f7a5260edffe 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -16,6 +16,7 @@ #include #include +#include #include struct tegra_regulator_coupler { @@ -39,6 +40,21 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, int core_cur_uV; int err; + /* + * Tegra30 SoC has critical DVFS-capable devices that are + * permanently-active or active at a boot time, like EMC + * (DRAM controller) or Host1x bus for example. + * + * The voltage of a CORE SoC power domain shall not be dropped below + * a minimum level, which is determined by device's clock rate. + * This means that we can't fully allow CORE voltage scaling until + * the state of all DVFS-critical CORE devices is synced. + */ + if (tegra_soc_dvfs_state_synced()) { + pr_info_once("voltage state synced\n"); + return 0; + } + if (tegra->core_min_uV > 0) return tegra->core_min_uV; @@ -59,7 +75,7 @@ static int tegra30_core_limit(struct tegra_regulator_coupler *tegra, */ tegra->core_min_uV = core_max_uV; - pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV); + pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); return tegra->core_min_uV; } @@ -143,6 +159,10 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (core_min_uV < 0) return core_min_uV; + err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV); + if (err) + return err; + err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV, PM_SUSPEND_ON); if (err) -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:06 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:06 +0300 Subject: [PATCH v1 09/30] soc/tegra: regulators: Fix lockup when voltage-spread is out of range In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-10-digetx@gmail.com> Fix voltage coupler lockup which happens when voltage-spread is out of range due to a bug in the code. The max-spread requirement shall be accounted when CPU regulator doesn't have consumers. This problem is observed on Tegra30 Ouya game console once system-wide DVFS is enabled in a device-tree. Fixes: 783807436f36 ("soc/tegra: regulators: Add regulators coupler for Tegra30") Cc: stable at vger.kernel.org Tested-by: Peter Geis Reported-by: Peter Geis Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/regulators-tegra30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index f7a5260edffe..fcf824f73131 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -198,7 +198,7 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, * survive the voltage drop if it's running on a higher frequency. */ if (!cpu_min_uV_consumers) - cpu_min_uV = cpu_uV; + cpu_min_uV = max(cpu_uV, cpu_min_uV); /* * Bootloader shall set up voltages correctly, but if it -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:08 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:08 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-12-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the display controller driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/Kconfig | 1 + drivers/gpu/drm/tegra/dc.c | 138 +++++++++++++++++++++++++++++++++- drivers/gpu/drm/tegra/dc.h | 5 ++ 3 files changed, 143 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 1650a448eabd..9eec4c3fbd3b 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -12,6 +12,7 @@ config DRM_TEGRA select INTERCONNECT select IOMMU_IOVA select CEC_CORE if CEC_NOTIFIER + select PM_OPP help Choose this option if you have an NVIDIA Tegra SoC. diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index fd7c8828652d..babcb66a335b 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -11,9 +11,13 @@ #include #include #include +#include #include +#include #include +#include +#include #include #include @@ -1699,6 +1703,55 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc, return 0; } +static void tegra_dc_update_voltage_state(struct tegra_dc *dc, + struct tegra_dc_state *state) +{ + struct dev_pm_opp *opp; + unsigned long rate; + int err, min_uV; + + /* OPP usage is optional */ + if (!dc->opp_table) + return; + + /* calculate actual pixel clock rate which depends on internal divider */ + rate = DIV_ROUND_UP(clk_get_rate(dc->clk) * 2, state->div + 2); + + /* find suitable OPP for the rate */ + opp = dev_pm_opp_find_freq_ceil(dc->dev, &rate); + + if (opp == ERR_PTR(-ERANGE)) + opp = dev_pm_opp_find_freq_floor(dc->dev, &rate); + + if (IS_ERR(opp)) { + dev_err(dc->dev, "failed to find OPP for %lu Hz: %ld\n", + rate, PTR_ERR(opp)); + return; + } + + min_uV = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + + /* + * Voltage scaling is optional and trying to set voltage for a dummy + * regulator will error out. + */ + if (!device_property_present(dc->dev, "core-supply")) + return; + + /* + * Note that the minimum core voltage depends on the pixel clock + * rate (which depends on internal clock divider of CRTC) and not on + * the rate of the display controller clock. This is why we're not + * using dev_pm_opp_set_rate() API and instead are managing the + * voltage by ourselves. + */ + err = regulator_set_voltage(dc->core_reg, min_uV, INT_MAX); + if (err) + dev_err(dc->dev, "failed to set CORE voltage to %duV: %d\n", + min_uV, err); +} + static void tegra_dc_commit_state(struct tegra_dc *dc, struct tegra_dc_state *state) { @@ -1738,6 +1791,8 @@ static void tegra_dc_commit_state(struct tegra_dc *dc, if (err < 0) dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n", dc->clk, state->pclk, err); + + tegra_dc_update_voltage_state(dc, state); } static void tegra_dc_stop(struct tegra_dc *dc) @@ -2521,6 +2576,7 @@ static int tegra_dc_runtime_suspend(struct host1x_client *client) clk_disable_unprepare(dc->clk); pm_runtime_put_sync(dev); + regulator_disable(dc->core_reg); return 0; } @@ -2531,10 +2587,16 @@ static int tegra_dc_runtime_resume(struct host1x_client *client) struct device *dev = client->dev; int err; + err = regulator_enable(dc->core_reg); + if (err < 0) { + dev_err(dev, "failed to enable CORE regulator: %d\n", err); + return err; + } + err = pm_runtime_get_sync(dev); if (err < 0) { dev_err(dev, "failed to get runtime PM: %d\n", err); - return err; + goto disable_regulator; } if (dc->soc->has_powergate) { @@ -2564,6 +2626,9 @@ static int tegra_dc_runtime_resume(struct host1x_client *client) clk_disable_unprepare(dc->clk); put_rpm: pm_runtime_put_sync(dev); +disable_regulator: + regulator_disable(dc->core_reg); + return err; } @@ -2879,6 +2944,72 @@ static int tegra_dc_couple(struct tegra_dc *dc) return 0; } +static void tegra_dc_deinit_opp_table(void *data) +{ + struct tegra_dc *dc = data; + + dev_pm_opp_of_remove_table(dc->dev); + dev_pm_opp_put_supported_hw(dc->opp_table); + dev_pm_opp_put_regulators(dc->opp_table); +} + +static int devm_tegra_dc_opp_table_init(struct tegra_dc *dc) +{ + struct opp_table *hw_opp_table; + u32 hw_version; + int err; + + /* voltage scaling is optional */ + dc->core_reg = devm_regulator_get(dc->dev, "core"); + if (IS_ERR(dc->core_reg)) + return dev_err_probe(dc->dev, PTR_ERR(dc->core_reg), + "failed to get CORE regulator\n"); + + /* legacy device-trees don't have OPP table */ + if (!device_property_present(dc->dev, "operating-points-v2")) + return 0; + + dc->opp_table = dev_pm_opp_get_opp_table(dc->dev); + if (IS_ERR(dc->opp_table)) + return dev_err_probe(dc->dev, PTR_ERR(dc->opp_table), + "failed to prepare OPP table\n"); + + if (of_machine_is_compatible("nvidia,tegra20")) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + hw_opp_table = dev_pm_opp_set_supported_hw(dc->dev, &hw_version, 1); + err = PTR_ERR_OR_ZERO(hw_opp_table); + if (err) { + dev_err(dc->dev, "failed to set supported HW: %d\n", err); + goto put_table; + } + + err = dev_pm_opp_of_add_table(dc->dev); + if (err) { + dev_err(dc->dev, "failed to add OPP table: %d\n", err); + goto put_hw; + } + + err = devm_add_action(dc->dev, tegra_dc_deinit_opp_table, dc); + if (err) + goto remove_table; + + dev_info(dc->dev, "OPP HW ver. 0x%x\n", hw_version); + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dc->dev); +put_hw: + dev_pm_opp_put_supported_hw(dc->opp_table); +put_table: + dev_pm_opp_put_opp_table(dc->opp_table); + + return err; +} + static int tegra_dc_probe(struct platform_device *pdev) { struct tegra_dc *dc; @@ -2937,6 +3068,10 @@ static int tegra_dc_probe(struct platform_device *pdev) tegra_powergate_power_off(dc->powergate); } + err = devm_tegra_dc_opp_table_init(dc); + if (err < 0) + return err; + dc->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dc->regs)) return PTR_ERR(dc->regs); @@ -3007,6 +3142,7 @@ struct platform_driver tegra_dc_driver = { .driver = { .name = "tegra-dc", .of_match_table = tegra_dc_of_match, + .sync_state = tegra_soc_device_sync_state, }, .probe = tegra_dc_probe, .remove = tegra_dc_remove, diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index ba4ed35139fb..fd774fc5c2e4 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -13,6 +13,8 @@ #include "drm.h" +struct opp_table; +struct regulator; struct tegra_output; #define TEGRA_DC_LEGACY_PLANES_NUM 6 @@ -107,6 +109,9 @@ struct tegra_dc { struct drm_info_list *debugfs_files; const struct tegra_dc_soc_info *soc; + + struct opp_table *opp_table; + struct regulator *core_reg; }; static inline struct tegra_dc * -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:04 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:04 +0300 Subject: [PATCH v1 07/30] soc/tegra: Add sync state API In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-8-digetx@gmail.com> Introduce sync state API that will be used by Tegra device drivers. This new API is primarily needed for syncing state of SoC devices that are left ON after bootloader or permanently enabled. All these devices belong to a shared CORE voltage domain, and thus, we needed to bring all the devices into expected state before the voltage scaling could be performed. All drivers of DVFS-critical devices shall sync theirs the state before Tegra's voltage regulator coupler will be allowed to perform a system-wide voltage scaling. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/soc/tegra/common.c | 152 ++++++++++++++++++++++++++++++++++++- include/soc/tegra/common.h | 22 ++++++ 2 files changed, 170 insertions(+), 4 deletions(-) diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 3dc54f59cafe..f9b2b6f57887 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -3,13 +3,52 @@ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. */ +#define dev_fmt(fmt) "%s: " fmt, __func__ +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include #include +#include #include +#define terga_soc_for_each_device(__dev) \ + for ((__dev) = tegra_soc_devices; (__dev) && (__dev)->compatible; \ + (__dev)++) + +struct tegra_soc_device { + const char *compatible; + const bool dvfs_critical; + unsigned int sync_count; +}; + +static DEFINE_MUTEX(tegra_soc_lock); +static struct tegra_soc_device *tegra_soc_devices; + +/* + * DVFS-critical devices are either active at a boot time or permanently + * active, like EMC for example. System-wide DVFS should be deferred until + * drivers of the critical devices synced theirs state. + */ + +static struct tegra_soc_device tegra20_soc_devices[] = { + { .compatible = "nvidia,tegra20-dc", .dvfs_critical = true, }, + { .compatible = "nvidia,tegra20-emc", .dvfs_critical = true, }, + { } +}; + +static struct tegra_soc_device tegra30_soc_devices[] = { + { .compatible = "nvidia,tegra30-dc", .dvfs_critical = true, }, + { .compatible = "nvidia,tegra30-emc", .dvfs_critical = true, }, + { .compatible = "nvidia,tegra30-pwm", .dvfs_critical = true, }, + { } +}; + static const struct of_device_id tegra_machine_match[] = { - { .compatible = "nvidia,tegra20", }, - { .compatible = "nvidia,tegra30", }, + { .compatible = "nvidia,tegra20", .data = tegra20_soc_devices, }, + { .compatible = "nvidia,tegra30", .data = tegra30_soc_devices, }, { .compatible = "nvidia,tegra114", }, { .compatible = "nvidia,tegra124", }, { .compatible = "nvidia,tegra132", }, @@ -17,7 +56,7 @@ static const struct of_device_id tegra_machine_match[] = { { } }; -bool soc_is_tegra(void) +static const struct of_device_id *tegra_soc_of_match(void) { const struct of_device_id *match; struct device_node *root; @@ -29,5 +68,110 @@ bool soc_is_tegra(void) match = of_match_node(tegra_machine_match, root); of_node_put(root); - return match != NULL; + return match; +} + +bool soc_is_tegra(void) +{ + return tegra_soc_of_match() != NULL; +} + +void tegra_soc_device_sync_state(struct device *dev) +{ + struct tegra_soc_device *soc_dev; + + mutex_lock(&tegra_soc_lock); + terga_soc_for_each_device(soc_dev) { + if (!of_device_is_compatible(dev->of_node, soc_dev->compatible)) + continue; + + if (!soc_dev->sync_count) { + dev_err(dev, "already synced\n"); + break; + } + + /* + * All DVFS-capable devices should have the CORE regulator + * phandle. Older device-trees don't have it, hence state + * won't be synced for the older DTBs, allowing them to work + * properly. + */ + if (soc_dev->dvfs_critical && + !device_property_present(dev, "core-supply")) { + dev_dbg(dev, "doesn't have core supply\n"); + break; + } + + soc_dev->sync_count--; + dev_dbg(dev, "sync_count=%u\n", soc_dev->sync_count); + break; + } + mutex_unlock(&tegra_soc_lock); +} +EXPORT_SYMBOL_GPL(tegra_soc_device_sync_state); + +bool tegra_soc_dvfs_state_synced(void) +{ + struct tegra_soc_device *soc_dev; + bool synced_state = true; + + /* + * CORE voltage scaling is limited until drivers of the critical + * devices synced theirs state. + */ + mutex_lock(&tegra_soc_lock); + terga_soc_for_each_device(soc_dev) { + if (!soc_dev->sync_count || !soc_dev->dvfs_critical) + continue; + + pr_debug_ratelimited("%s: sync_count=%u\n", + soc_dev->compatible, soc_dev->sync_count); + + synced_state = false; + break; + } + mutex_unlock(&tegra_soc_lock); + + return synced_state; +} + +static int __init tegra_soc_devices_init(void) +{ + struct device_node *np, *prev_np = NULL; + struct tegra_soc_device *soc_dev; + const struct of_device_id *match; + + if (!soc_is_tegra()) + return 0; + + match = tegra_soc_of_match(); + tegra_soc_devices = (void *)match->data; + + /* + * If device node is disabled in a device-tree, then we shouldn't + * care about this device. Even if device is active during boot, + * its clock will be disabled by CCF as unused. + */ + terga_soc_for_each_device(soc_dev) { + do { + /* + * Devices like display controller have multiple + * instances with the same compatible. Hence we need + * to walk up the whole tree in order to account those + * multiple instances. + */ + np = of_find_compatible_node(prev_np, NULL, + soc_dev->compatible); + of_node_put(prev_np); + prev_np = np; + + if (of_device_is_available(np)) { + pr_debug("added %s\n", soc_dev->compatible); + soc_dev->sync_count++; + } + } while (np); + } + + return 0; } +postcore_initcall_sync(tegra_soc_devices_init); diff --git a/include/soc/tegra/common.h b/include/soc/tegra/common.h index 98027a76ce3d..d3ddb96d0fe2 100644 --- a/include/soc/tegra/common.h +++ b/include/soc/tegra/common.h @@ -6,6 +6,28 @@ #ifndef __SOC_TEGRA_COMMON_H__ #define __SOC_TEGRA_COMMON_H__ +#include + +struct device; + +#ifdef CONFIG_ARCH_TEGRA bool soc_is_tegra(void); +void tegra_soc_device_sync_state(struct device *dev); +bool tegra_soc_dvfs_state_synced(void); +#else +static inline bool soc_is_tegra(void) +{ + return false; +} + +static inline void tegra_soc_device_sync_state(struct device *dev) +{ +} + +static inline tegra_soc_dvfs_state_synced(void) +{ + return false; +} +#endif #endif /* __SOC_TEGRA_COMMON_H__ */ -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:07 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:07 +0300 Subject: [PATCH v1 10/30] regulator: Allow skipping disabled regulators in regulator_check_consumers() In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-11-digetx@gmail.com> Add option which allows regulator_check_consumers() to skip accounting of a disabled consumer regulators. This new option is needed for the NVIDIA Tegra voltage couplers in order to properly calculate a lowest possible voltage for the CORE regulator. The requirements of a disabled consumer regulators should not be accounted by the Tegra voltage balancers because disabled state means that hardware is inactive. In particular disabled state shouldn't be accounted for the consumers which belong to the CORE voltage domain, meanwhile CPU domain should continue to account the disabled state. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/regulator/core.c | 12 ++++++++---- drivers/soc/samsung/exynos-regulator-coupler.c | 2 +- drivers/soc/tegra/regulators-tegra20.c | 6 +++--- drivers/soc/tegra/regulators-tegra30.c | 6 +++--- include/linux/regulator/coupler.h | 6 ++++-- 5 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f258ded39ce0..015dcd8408d9 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -462,7 +462,8 @@ static int regulator_check_states(suspend_state_t state) */ int regulator_check_consumers(struct regulator_dev *rdev, int *min_uV, int *max_uV, - suspend_state_t state) + suspend_state_t state, + bool skip_disabled_regulators) { struct regulator *regulator; struct regulator_voltage *voltage; @@ -476,6 +477,9 @@ int regulator_check_consumers(struct regulator_dev *rdev, if (!voltage->min_uV && !voltage->max_uV) continue; + if (skip_disabled_regulators && !regulator->enable_count) + continue; + if (*max_uV > voltage->max_uV) *max_uV = voltage->max_uV; if (*min_uV < voltage->min_uV) @@ -3662,7 +3666,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, ret = regulator_check_consumers(rdev, &desired_min_uV, - &desired_max_uV, state); + &desired_max_uV, state, false); if (ret < 0) return ret; @@ -3681,7 +3685,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, ret = regulator_check_consumers(c_rdevs[i], &tmp_min, - &tmp_max, state); + &tmp_max, state, false); if (ret < 0) return ret; @@ -4119,7 +4123,7 @@ int regulator_sync_voltage(struct regulator *regulator) if (ret < 0) goto out; - ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0); + ret = regulator_check_consumers(rdev, &min_uV, &max_uV, 0, false); if (ret < 0) goto out; diff --git a/drivers/soc/samsung/exynos-regulator-coupler.c b/drivers/soc/samsung/exynos-regulator-coupler.c index 61a156b44a48..9bd99a93e3e0 100644 --- a/drivers/soc/samsung/exynos-regulator-coupler.c +++ b/drivers/soc/samsung/exynos-regulator-coupler.c @@ -41,7 +41,7 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev, ret = regulator_check_consumers(c_rdevs[i], &tmp_min, - &tmp_max, state); + &tmp_max, state, false); if (ret < 0) return ret; diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index 8782e399a58c..8c31acb5fdc6 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -136,7 +136,7 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, return err; err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV, - PM_SUSPEND_ON); + PM_SUSPEND_ON, true); if (err) return err; @@ -246,12 +246,12 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, return err; err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV, - PM_SUSPEND_ON); + PM_SUSPEND_ON, false); if (err) return err; err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers, - &cpu_max_uV, PM_SUSPEND_ON); + &cpu_max_uV, PM_SUSPEND_ON, false); if (err) return err; diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index fcf824f73131..d92aafa736bc 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -164,7 +164,7 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, return err; err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV, - PM_SUSPEND_ON); + PM_SUSPEND_ON, true); if (err) return err; @@ -175,12 +175,12 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, cpu_min_uV = core_min_uV - max_spread; err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV, - PM_SUSPEND_ON); + PM_SUSPEND_ON, false); if (err) return err; err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers, - &cpu_max_uV, PM_SUSPEND_ON); + &cpu_max_uV, PM_SUSPEND_ON, false); if (err) return err; diff --git a/include/linux/regulator/coupler.h b/include/linux/regulator/coupler.h index 5f86824bd117..4e076567b823 100644 --- a/include/linux/regulator/coupler.h +++ b/include/linux/regulator/coupler.h @@ -55,7 +55,8 @@ int regulator_coupler_register(struct regulator_coupler *coupler); const char *rdev_get_name(struct regulator_dev *rdev); int regulator_check_consumers(struct regulator_dev *rdev, int *min_uV, int *max_uV, - suspend_state_t state); + suspend_state_t state, + bool skip_disabled_regulators); int regulator_check_voltage(struct regulator_dev *rdev, int *min_uV, int *max_uV); int regulator_get_voltage_rdev(struct regulator_dev *rdev); @@ -75,7 +76,8 @@ static inline const char *rdev_get_name(struct regulator_dev *rdev) } static inline int regulator_check_consumers(struct regulator_dev *rdev, int *min_uV, int *max_uV, - suspend_state_t state) + suspend_state_t state, + bool skip_disabled_regulators)) { return -EINVAL; } -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:09 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:09 +0300 Subject: [PATCH v1 12/30] drm/tegra: gr2d: Correct swapped device-tree compatibles In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-13-digetx@gmail.com> The device-tree compatibles are swapped in the code, correct them. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/gr2d.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 1a0d3ba6e525..f30aa86e4c9f 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -162,8 +162,8 @@ static const struct gr2d_soc tegra30_gr2d_soc = { }; static const struct of_device_id gr2d_match[] = { - { .compatible = "nvidia,tegra30-gr2d", .data = &tegra20_gr2d_soc }, - { .compatible = "nvidia,tegra20-gr2d", .data = &tegra30_gr2d_soc }, + { .compatible = "nvidia,tegra30-gr2d", .data = &tegra30_gr2d_soc }, + { .compatible = "nvidia,tegra20-gr2d", .data = &tegra20_gr2d_soc }, { }, }; MODULE_DEVICE_TABLE(of, gr2d_match); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:10 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:10 +0300 Subject: [PATCH v1 13/30] drm/tegra: gr2d: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-14-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the GR2D driver. This is required for enabling system-wide DVFS on Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/gr2d.c | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index f30aa86e4c9f..6d8f9419d908 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -7,6 +7,9 @@ #include #include #include +#include + +#include #include "drm.h" #include "gem.h" @@ -185,6 +188,135 @@ static const u32 gr2d_addr_regs[] = { GR2D_VA_BASE_ADDR_SB, }; +static int gr2d_init_opp_state(struct device *dev, struct gr2d *gr2d) +{ + struct dev_pm_opp *opp; + unsigned long rate; + int err; + + /* + * If voltage regulator presents, then we could select the fastest + * clock rate, but driver doesn't support power management and + * frequency scaling yet, hence the top freq OPP will vote for a + * very high voltage that will produce lot's of heat. Let's select + * OPP for the current/default rate for now. + * + * Clock rate should be pre-initialized (i.e. it's non-zero) either + * by clock driver or by assigned clocks in a device-tree. + */ + rate = clk_get_rate(gr2d->clk); + + /* find suitable OPP for the clock rate supportable by SoC speedo ID */ + opp = dev_pm_opp_find_freq_ceil(dev, &rate); + + /* + * dev_pm_opp_set_rate() doesn't search for a floor clock rate and it + * will error out if default clock rate is too high, i.e. unsupported + * by a SoC hardware version. Hence will find floor rate by ourselves. + */ + if (opp == ERR_PTR(-ERANGE)) + opp = dev_pm_opp_find_freq_floor(dev, &rate); + + err = PTR_ERR_OR_ZERO(opp); + if (err) { + dev_err(dev, "failed to get OPP for %ld Hz: %d\n", + rate, err); + return err; + } + + dev_pm_opp_put(opp); + + /* + * First dummy rate-set initializes voltage vote by setting voltage + * in accordance to the clock rate. We need to do this because GR2D + * currently doesn't support power management and clock is permanently + * enabled. + */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + return err; + } + + return 0; +} + +static void gr2d_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_supported_hw(opp_table); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_gr2d_init_opp_table(struct device *dev, struct gr2d *gr2d) +{ + struct opp_table *opp_table, *hw_opp_table; + const char *rname = "core"; + u32 hw_version; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + if (gr2d->soc->version == 0x20) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + hw_opp_table = dev_pm_opp_set_supported_hw(dev, &hw_version, 1); + err = PTR_ERR_OR_ZERO(hw_opp_table); + if (err) { + dev_err(dev, "failed to set supported HW: %d\n", err); + goto put_table; + } + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_hw; + } + + err = gr2d_init_opp_state(dev, gr2d); + if (err) + goto remove_table; + } + + err = devm_add_action(dev, gr2d_deinit_opp_table, dev); + if (err) + goto remove_table; + + dev_info(dev, "OPP HW ver. 0x%x\n", hw_version); + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_hw: + dev_pm_opp_put_supported_hw(opp_table); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int gr2d_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -209,6 +341,10 @@ static int gr2d_probe(struct platform_device *pdev) return PTR_ERR(gr2d->clk); } + err = devm_gr2d_init_opp_table(dev, gr2d); + if (err) + return dev_err_probe(dev, err, "failed to initialize OPP\n"); + err = clk_prepare_enable(gr2d->clk); if (err) { dev_err(dev, "cannot turn on clock\n"); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:12 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:12 +0300 Subject: [PATCH v1 15/30] drm/tegra: hdmi: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-16-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the HDMI driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/hdmi.c | 63 +++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index d09a24931c87..92e96990854b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1195,7 +1196,7 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) h_back_porch = mode->htotal - mode->hsync_end; h_front_porch = mode->hsync_start - mode->hdisplay; - err = clk_set_rate(hdmi->clk, hdmi->pixel_clock); + err = dev_pm_opp_set_rate(hdmi->dev, hdmi->pixel_clock); if (err < 0) { dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n", err); @@ -1499,6 +1500,7 @@ static int tegra_hdmi_runtime_suspend(struct host1x_client *client) usleep_range(1000, 2000); clk_disable_unprepare(hdmi->clk); + dev_pm_opp_set_rate(hdmi->dev, 0); pm_runtime_put_sync(dev); return 0; @@ -1633,6 +1635,60 @@ static irqreturn_t tegra_hdmi_irq(int irq, void *data) return IRQ_HANDLED; } +static void tegra_hdmi_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_tegra_hdmi_init_opp_table(struct device *dev) +{ + struct opp_table *opp_table; + const char *rname = "core"; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_table; + } + } + + err = devm_add_action(dev, tegra_hdmi_deinit_opp_table, dev); + if (err) + goto remove_table; + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int tegra_hdmi_probe(struct platform_device *pdev) { const char *level = KERN_ERR; @@ -1667,6 +1723,11 @@ static int tegra_hdmi_probe(struct platform_device *pdev) if (IS_ERR(hdmi->clk_parent)) return PTR_ERR(hdmi->clk_parent); + err = devm_tegra_hdmi_init_opp_table(&pdev->dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to initialize OPP\n"); + err = clk_set_parent(hdmi->clk, hdmi->clk_parent); if (err < 0) { dev_err(&pdev->dev, "failed to setup clocks: %d\n", err); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:11 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:11 +0300 Subject: [PATCH v1 14/30] drm/tegra: gr3d: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-15-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the GR3D driver. This is required for enabling system-wide DVFS on Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/gpu/drm/tegra/gr3d.c | 136 +++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index b0b8154e8104..0c6efc55f9bc 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -11,7 +11,9 @@ #include #include #include +#include +#include #include #include "drm.h" @@ -278,6 +280,135 @@ static const u32 gr3d_addr_regs[] = { GR3D_GLOBAL_SAMP23SURFADDR(15), }; +static int gr3d_init_opp_state(struct device *dev, struct gr3d *gr3d) +{ + struct dev_pm_opp *opp; + unsigned long rate; + int err; + + /* + * If voltage regulator presents, then we could select the fastest + * clock rate, but driver doesn't support power management and + * frequency scaling yet, hence the top freq OPP will vote for a + * very high voltage that will produce lot's of heat. Let's select + * OPP for the current/default rate for now. + * + * Clock rate should be pre-initialized (i.e. it's non-zero) either + * by clock driver or by assigned clocks in a device-tree. + */ + rate = clk_get_rate(gr3d->clk); + + /* find suitable OPP for the clock rate supportable by SoC speedo ID */ + opp = dev_pm_opp_find_freq_ceil(dev, &rate); + + /* + * dev_pm_opp_set_rate() doesn't search for a floor clock rate and it + * will error out if default clock rate is too high, i.e. unsupported + * by a SoC hardware version. Hence will find floor rate by ourselves. + */ + if (opp == ERR_PTR(-ERANGE)) + opp = dev_pm_opp_find_freq_floor(dev, &rate); + + err = PTR_ERR_OR_ZERO(opp); + if (err) { + dev_err(dev, "failed to get OPP for %ld Hz: %d\n", + rate, err); + return err; + } + + dev_pm_opp_put(opp); + + /* + * First dummy rate-set initializes voltage vote by setting voltage + * in accordance to the clock rate. We need to do this because GR2D + * currently doesn't support power management and clock is permanently + * enabled. + */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + return err; + } + + return 0; +} + +static void gr3d_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_supported_hw(opp_table); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_gr3d_init_opp_table(struct device *dev, struct gr3d *gr3d) +{ + struct opp_table *opp_table, *hw_opp_table; + const char *rname = "core"; + u32 hw_version; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + if (gr3d->soc->version == 0x20) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + hw_opp_table = dev_pm_opp_set_supported_hw(dev, &hw_version, 1); + err = PTR_ERR_OR_ZERO(hw_opp_table); + if (err) { + dev_err(dev, "failed to set supported HW: %d\n", err); + goto put_table; + } + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_hw; + } + + err = gr3d_init_opp_state(dev, gr3d); + if (err) + goto remove_table; + } + + err = devm_add_action(dev, gr3d_deinit_opp_table, dev); + if (err) + goto remove_table; + + dev_info(dev, "OPP HW ver. 0x%x\n", hw_version); + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_hw: + dev_pm_opp_put_supported_hw(opp_table); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int gr3d_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -302,6 +433,11 @@ static int gr3d_probe(struct platform_device *pdev) return PTR_ERR(gr3d->clk); } + err = devm_gr3d_init_opp_table(&pdev->dev, gr3d); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to initialize OPP\n"); + gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); if (IS_ERR(gr3d->rst)) { dev_err(&pdev->dev, "cannot get reset\n"); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:13 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:13 +0300 Subject: [PATCH v1 16/30] gpu: host1x: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-17-digetx@gmail.com> Add initial OPP and SoC core voltage scaling support to the Host1x driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/gpu/host1x/Kconfig | 1 + drivers/gpu/host1x/dev.c | 87 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig index 6dab94adf25e..fba4207c35a4 100644 --- a/drivers/gpu/host1x/Kconfig +++ b/drivers/gpu/host1x/Kconfig @@ -3,6 +3,7 @@ config TEGRA_HOST1X tristate "NVIDIA Tegra host1x driver" depends on ARCH_TEGRA || (ARM && COMPILE_TEST) select IOMMU_IOVA + select PM_OPP help Driver for the NVIDIA Tegra host1x hardware. diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index d0ebb70e2fdd..06e65dc1ab19 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -13,6 +13,9 @@ #include #include #include +#include + +#include #define CREATE_TRACE_POINTS #include @@ -341,6 +344,85 @@ static void host1x_iommu_exit(struct host1x *host) } } +static void host1x_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_supported_hw(opp_table); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_host1x_init_opp_table(struct host1x *host) +{ + struct opp_table *opp_table, *hw_opp_table; + const char *rname = "core"; + u32 hw_version; + int err; + + /* voltage scaling is optional */ + if (device_property_present(host->dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(host->dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(host->dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(host->dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + if (of_machine_is_compatible("nvidia,tegra20")) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + hw_opp_table = dev_pm_opp_set_supported_hw(host->dev, &hw_version, 1); + err = PTR_ERR_OR_ZERO(hw_opp_table); + if (err) { + dev_err(host->dev, "failed to set supported HW: %d\n", err); + goto put_table; + } + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(host->dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(host->dev); + if (err) { + dev_err(host->dev, "failed to add OPP table: %d\n", err); + goto put_hw; + } + } + + /* first dummy rate-set initializes voltage vote */ + err = dev_pm_opp_set_rate(host->dev, clk_get_rate(host->clk)); + if (err) { + dev_err(host->dev, "failed to initialize OPP clock: %d\n", err); + goto remove_table; + } + + err = devm_add_action(host->dev, host1x_deinit_opp_table, host->dev); + if (err) + goto remove_table; + + dev_info(host->dev, "OPP HW ver. 0x%x\n", hw_version); + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(host->dev); +put_hw: + dev_pm_opp_put_supported_hw(opp_table); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int host1x_probe(struct platform_device *pdev) { struct host1x *host; @@ -424,6 +506,11 @@ static int host1x_probe(struct platform_device *pdev) return err; } + err = devm_host1x_init_opp_table(host); + if (err < 0) + return dev_err_probe(&pdev->dev, err, + "failed to initialize OPP\n"); + err = host1x_iommu_init(host); if (err < 0) { dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:14 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:14 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-18-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the Tegra SDHCI driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/mmc/host/Kconfig | 1 + drivers/mmc/host/sdhci-tegra.c | 70 ++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 310e546e5898..7d719c81b917 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -293,6 +293,7 @@ config MMC_SDHCI_TEGRA depends on MMC_SDHCI_PLTFM select MMC_SDHCI_IO_ACCESSORS select MMC_CQHCI + select PM_OPP help This selects the Tegra SD/MMC controller. If you have a Tegra platform with SD or MMC devices, say Y or M here. diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index ed12aacb1c73..964709a3ccd6 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -754,10 +755,15 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_tegra *tegra_host = sdhci_pltfm_priv(pltfm_host); + struct device *dev = mmc_dev(host->mmc); unsigned long host_clk; - if (!clock) - return sdhci_set_clock(host, clock); + /* disable clock and then remove OPP performance/voltage vote */ + if (!clock) { + sdhci_set_clock(host, clock); + dev_pm_opp_set_rate(dev, clock); + return; + } /* * In DDR50/52 modes the Tegra SDHCI controllers require the SDHCI @@ -772,7 +778,7 @@ static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock) * from clk_get_rate() is used. */ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock; - clk_set_rate(pltfm_host->clk, host_clk); + dev_pm_opp_set_rate(dev, host_clk); tegra_host->curr_clk_rate = host_clk; if (tegra_host->ddr_signaling) host->max_clk = host_clk; @@ -1558,6 +1564,60 @@ static int sdhci_tegra_add_host(struct sdhci_host *host) return ret; } +static void sdhci_tegra_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_sdhci_tegra_init_opp_table(struct device *dev) +{ + struct opp_table *opp_table; + const char *rname = "core"; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_table; + } + } + + err = devm_add_action(dev, sdhci_tegra_deinit_opp_table, dev); + if (err) + goto remove_table; + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int sdhci_tegra_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -1621,6 +1681,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev) goto err_power_req; } + rc = devm_sdhci_tegra_init_opp_table(&pdev->dev); + if (rc) + goto err_parse_dt; + /* * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host * timeout clock and SW can choose TMCLK or SDCLK for hardware -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:15 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:15 +0300 Subject: [PATCH v1 18/30] pwm: tegra: Support OPP and core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-19-digetx@gmail.com> Add OPP and SoC core voltage scaling support to the Tegra PWM driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/pwm/Kconfig | 1 + drivers/pwm/pwm-tegra.c | 84 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 63be5362fd3a..61d35ef759f2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -509,6 +509,7 @@ config PWM_SUN4I config PWM_TEGRA tristate "NVIDIA Tegra PWM support" depends on ARCH_TEGRA || COMPILE_TEST + select PM_OPP help Generic PWM framework driver for the PWFM controller found on NVIDIA Tegra SoCs. diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index 1daf591025c0..96c253127ff3 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -42,12 +42,15 @@ #include #include #include +#include #include #include #include #include #include +#include + #define PWM_ENABLE (1 << 31) #define PWM_DUTY_WIDTH 8 #define PWM_DUTY_SHIFT 16 @@ -145,7 +148,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, required_clk_rate = (NSEC_PER_SEC / period_ns) << PWM_DUTY_WIDTH; - err = clk_set_rate(pc->clk, required_clk_rate); + err = dev_pm_opp_set_rate(pc->dev, required_clk_rate); if (err < 0) return -EINVAL; @@ -181,6 +184,10 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * before writing the register. Otherwise, keep it enabled. */ if (!pwm_is_enabled(pwm)) { + err = dev_pm_opp_set_rate(pc->dev, pc->clk_rate); + if (err < 0) + return err; + err = clk_prepare_enable(pc->clk); if (err < 0) return err; @@ -191,9 +198,12 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * If the PWM is not enabled, turn the clock off again to save power. + * Remove OPP performance/voltage vote after disabling the clock. */ - if (!pwm_is_enabled(pwm)) + if (!pwm_is_enabled(pwm)) { clk_disable_unprepare(pc->clk); + dev_pm_opp_set_rate(pc->dev, 0); + } return 0; } @@ -204,6 +214,10 @@ static int tegra_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) int rc = 0; u32 val; + rc = dev_pm_opp_set_rate(pc->dev, pc->clk_rate); + if (rc < 0) + return rc; + rc = clk_prepare_enable(pc->clk); if (rc < 0) return rc; @@ -225,6 +239,7 @@ static void tegra_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) pwm_writel(pc, pwm->hwpwm, val); clk_disable_unprepare(pc->clk); + dev_pm_opp_set_rate(pc->dev, 0); } static const struct pwm_ops tegra_pwm_ops = { @@ -234,6 +249,60 @@ static const struct pwm_ops tegra_pwm_ops = { .owner = THIS_MODULE, }; +static void tegra_pwm_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_tegra_pwm_init_opp_table(struct device *dev) +{ + struct opp_table *opp_table; + const char *rname = "core"; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + */ + if (device_property_present(dev, "operating-points-v2")) { + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_table; + } + } + + err = devm_add_action(dev, tegra_pwm_deinit_opp_table, dev); + if (err) + goto remove_table; + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int tegra_pwm_probe(struct platform_device *pdev) { struct tegra_pwm_chip *pwm; @@ -258,8 +327,12 @@ static int tegra_pwm_probe(struct platform_device *pdev) if (IS_ERR(pwm->clk)) return PTR_ERR(pwm->clk); + ret = devm_tegra_pwm_init_opp_table(&pdev->dev); + if (ret) + return ret; + /* Set maximum frequency of the IP */ - ret = clk_set_rate(pwm->clk, pwm->soc->max_frequency); + ret = dev_pm_opp_set_rate(pwm->dev, pwm->soc->max_frequency); if (ret < 0) { dev_err(&pdev->dev, "Failed to set max frequency: %d\n", ret); return ret; @@ -309,6 +382,10 @@ static int tegra_pwm_remove(struct platform_device *pdev) if (WARN_ON(!pc)) return -ENODEV; + err = dev_pm_opp_set_rate(pc->dev, pc->clk_rate); + if (err < 0) + return err; + err = clk_prepare_enable(pc->clk); if (err < 0) return err; @@ -375,6 +452,7 @@ static struct platform_driver tegra_pwm_driver = { .name = "tegra-pwm", .of_match_table = tegra_pwm_of_match, .pm = &tegra_pwm_pm_ops, + .sync_state = tegra_soc_device_sync_state, }, .probe = tegra_pwm_probe, .remove = tegra_pwm_remove, -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:16 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:16 +0300 Subject: [PATCH v1 19/30] media: staging: tegra-vde: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-20-digetx@gmail.com> Add initial OPP and SoC core voltage scaling support to the video decoder driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/staging/media/tegra-vde/Kconfig | 1 + drivers/staging/media/tegra-vde/vde.c | 127 ++++++++++++++++++++++++ drivers/staging/media/tegra-vde/vde.h | 1 + 3 files changed, 129 insertions(+) diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig index 0dc78afd09e0..0ebfe5b07a30 100644 --- a/drivers/staging/media/tegra-vde/Kconfig +++ b/drivers/staging/media/tegra-vde/Kconfig @@ -4,6 +4,7 @@ config TEGRA_VDE depends on ARCH_TEGRA || COMPILE_TEST select DMA_SHARED_BUFFER select IOMMU_IOVA + select PM_OPP select SRAM help Say Y here to enable support for the NVIDIA Tegra video decoder diff --git a/drivers/staging/media/tegra-vde/vde.c b/drivers/staging/media/tegra-vde/vde.c index 28845b5bafaf..9ad43a862eef 100644 --- a/drivers/staging/media/tegra-vde/vde.c +++ b/drivers/staging/media/tegra-vde/vde.c @@ -15,11 +15,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include "uapi.h" @@ -926,6 +928,9 @@ static __maybe_unused int tegra_vde_runtime_suspend(struct device *dev) clk_disable_unprepare(vde->clk); + /* remove performance/voltage vote */ + dev_pm_opp_set_rate(dev, 0); + return 0; } @@ -934,6 +939,12 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev) struct tegra_vde *vde = dev_get_drvdata(dev); int err; + err = dev_pm_opp_set_rate(dev, vde->default_clk_rate); + if (err) { + dev_err(dev, "Failed to set clock rate: %d\n", err); + return err; + } + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_VDEC, vde->clk, vde->rst); if (err) { @@ -944,6 +955,118 @@ static __maybe_unused int tegra_vde_runtime_resume(struct device *dev) return 0; } +static void tegra_vde_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_supported_hw(opp_table); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_tegra_vde_init_opp_table(struct device *dev, + struct tegra_vde *vde) +{ + struct opp_table *opp_table, *hw_opp_table; + const char *rname = "core"; + struct dev_pm_opp *opp; + unsigned long rate; + u32 hw_version; + int err; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "Failed to prepare OPP table\n"); + + if (of_machine_is_compatible("nvidia,tegra20")) + hw_version = BIT(tegra_sku_info.soc_process_id); + else + hw_version = BIT(tegra_sku_info.soc_speedo_id); + + hw_opp_table = dev_pm_opp_set_supported_hw(dev, &hw_version, 1); + err = PTR_ERR_OR_ZERO(hw_opp_table); + if (err) { + dev_err(dev, "Failed to set supported HW: %d\n", err); + goto put_table; + } + + /* + * OPP table presence is optional and we want the set_rate() of OPP + * API to work similarly to clk_set_rate() if table is missing in a + * device-tree. The add_table() errors out if OPP is missing in DT. + * + * Clock rate should be pre-initialized (i.e. it's non-zero) either + * by clock driver or by assigned clocks in a device-tree. + */ + if (!device_property_present(dev, "operating-points-v2")) { + vde->default_clk_rate = clk_get_rate(vde->clk); + goto add_action; + } + + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "Failed to add OPP table: %d\n", err); + goto put_hw; + } + + /* + * If voltage regulator presents, then we could select the fastest + * clock rate, but driver doesn't support frequency scaling yet, + * hence the top freq OPP may vote for a very high voltage that will + * produce lot's of heat. Let's select OPP for the current/default + * rate for now. + * + * Clock rate should be pre-initialized (i.e. it's non-zero) either + * by clock driver or by assigned clocks in a device-tree. + */ + rate = clk_get_rate(vde->clk); + + /* find suitable OPP for the clock rate supportable by SoC */ + opp = dev_pm_opp_find_freq_ceil(dev, &rate); + + if (opp == ERR_PTR(-ERANGE)) + opp = dev_pm_opp_find_freq_floor(dev, &rate); + + err = PTR_ERR_OR_ZERO(opp); + if (err) { + dev_err(dev, "failed to get OPP for %ld Hz: %d\n", + rate, err); + goto remove_table; + } + + dev_pm_opp_put(opp); + + vde->default_clk_rate = clk_round_rate(vde->clk, rate); + +add_action: + err = devm_add_action(dev, tegra_vde_deinit_opp_table, dev); + if (err) + goto remove_table; + + dev_info(dev, "OPP HW ver. 0x%x, clock rate %lu MHz\n", + hw_version, vde->default_clk_rate / 1000000); + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_hw: + dev_pm_opp_put_supported_hw(opp_table); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int tegra_vde_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1024,6 +1147,10 @@ static int tegra_vde_probe(struct platform_device *pdev) return err; } + err = devm_tegra_vde_init_opp_table(dev, vde); + if (err) + return dev_err_probe(dev, err, "Failed to initialize OPP\n"); + vde->iram_pool = of_gen_pool_get(dev->of_node, "iram", 0); if (!vde->iram_pool) { dev_err(dev, "Could not get IRAM pool\n"); diff --git a/drivers/staging/media/tegra-vde/vde.h b/drivers/staging/media/tegra-vde/vde.h index 5561291b0c88..da83c2d6af8b 100644 --- a/drivers/staging/media/tegra-vde/vde.h +++ b/drivers/staging/media/tegra-vde/vde.h @@ -48,6 +48,7 @@ struct tegra_vde { struct iova_domain iova; struct iova *iova_resv_static_addresses; struct iova *iova_resv_last_page; + unsigned long default_clk_rate; dma_addr_t iram_lists_addr; u32 *iram; }; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:17 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:17 +0300 Subject: [PATCH v1 20/30] usb: chipidea: tegra: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-21-digetx@gmail.com> Add initial OPP and SoC CORE voltage scaling support to the Tegra UDC driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Signed-off-by: Dmitry Osipenko --- drivers/usb/chipidea/Kconfig | 1 + drivers/usb/chipidea/ci_hdrc_tegra.c | 79 ++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 8bafcfc6080d..6a5bc08711d6 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -56,6 +56,7 @@ config USB_CHIPIDEA_TEGRA tristate "Enable Tegra UDC glue driver" if EMBEDDED depends on OF depends on USB_CHIPIDEA_UDC + select PM_OPP default USB_CHIPIDEA endif diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 7455df0ede49..7f0403e810fe 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -47,6 +48,79 @@ static const struct of_device_id tegra_udc_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_udc_of_match); +static void tegra_udc_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_tegra_udc_init_opp_table(struct device *dev) +{ + unsigned long rate = ULONG_MAX; + struct opp_table *opp_table; + const char *rname = "core"; + struct dev_pm_opp *opp; + int err; + + /* legacy device-trees don't have OPP table */ + if (!device_property_present(dev, "operating-points-v2")) + return 0; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_table; + } + + /* find suitable OPP for the maximum clock rate */ + opp = dev_pm_opp_find_freq_floor(dev, &rate); + err = PTR_ERR_OR_ZERO(opp); + if (err) { + dev_err(dev, "failed to get OPP: %d\n", err); + goto remove_table; + } + + dev_pm_opp_put(opp); + + /* + * First dummy rate-set initializes voltage vote by setting voltage + * in accordance to the clock rate. + */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + goto remove_table; + } + + err = devm_add_action(dev, tegra_udc_deinit_opp_table, dev); + if (err) + goto remove_table; + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static int tegra_udc_probe(struct platform_device *pdev) { const struct tegra_udc_soc_info *soc; @@ -77,6 +151,11 @@ static int tegra_udc_probe(struct platform_device *pdev) return err; } + err = devm_tegra_udc_init_opp_table(&pdev->dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to initialize OPP\n"); + err = clk_prepare_enable(udc->clk); if (err < 0) { dev_err(&pdev->dev, "failed to enable clock: %d\n", err); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:18 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:18 +0300 Subject: [PATCH v1 21/30] usb: host: ehci-tegra: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-22-digetx@gmail.com> Add initial OPP and SoC core voltage scaling support to the Tegra EHCI driver. This is required for enabling system-wide DVFS on older Tegra SoCs. Tested-by: Peter Geis Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/usb/host/Kconfig | 1 + drivers/usb/host/ehci-tegra.c | 79 +++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index ab12c4bf0ef1..35c42bc05c5a 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -278,6 +278,7 @@ config USB_EHCI_TEGRA depends on ARCH_TEGRA select USB_EHCI_ROOT_HUB_TT select USB_TEGRA_PHY + select PM_OPP help This driver enables support for the internal USB Host Controllers found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 869d9c4de5fc..0976577f54b4 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -364,6 +365,79 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) free_dma_aligned_buffer(urb); } +static void tegra_ehci_deinit_opp_table(void *data) +{ + struct device *dev = data; + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); + dev_pm_opp_of_remove_table(dev); + dev_pm_opp_put_regulators(opp_table); + dev_pm_opp_put_opp_table(opp_table); +} + +static int devm_tegra_ehci_init_opp_table(struct device *dev) +{ + unsigned long rate = ULONG_MAX; + struct opp_table *opp_table; + const char *rname = "core"; + struct dev_pm_opp *opp; + int err; + + /* legacy device-trees don't have OPP table */ + if (!device_property_present(dev, "operating-points-v2")) + return 0; + + /* voltage scaling is optional */ + if (device_property_present(dev, "core-supply")) + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); + else + opp_table = dev_pm_opp_get_opp_table(dev); + + if (IS_ERR(opp_table)) + return dev_err_probe(dev, PTR_ERR(opp_table), + "failed to prepare OPP table\n"); + + err = dev_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "failed to add OPP table: %d\n", err); + goto put_table; + } + + /* find suitable OPP for the maximum clock rate */ + opp = dev_pm_opp_find_freq_floor(dev, &rate); + err = PTR_ERR_OR_ZERO(opp); + if (err) { + dev_err(dev, "failed to get OPP: %d\n", err); + goto remove_table; + } + + dev_pm_opp_put(opp); + + /* + * First dummy rate-set initializes voltage vote by setting voltage + * in accordance to the clock rate. + */ + err = dev_pm_opp_set_rate(dev, rate); + if (err) { + dev_err(dev, "failed to initialize OPP clock: %d\n", err); + goto remove_table; + } + + err = devm_add_action(dev, tegra_ehci_deinit_opp_table, dev); + if (err) + goto remove_table; + + return 0; + +remove_table: + dev_pm_opp_of_remove_table(dev); +put_table: + dev_pm_opp_put_regulators(opp_table); + + return err; +} + static const struct tegra_ehci_soc_config tegra30_soc_config = { .has_hostpc = true, }; @@ -431,6 +505,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_hcd_create; } + err = devm_tegra_ehci_init_opp_table(&pdev->dev); + if (err) + return dev_err_probe(&pdev->dev, err, + "Failed to initialize OPP\n"); + err = clk_prepare_enable(tegra->clk); if (err) goto cleanup_hcd_create; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:19 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:19 +0300 Subject: [PATCH v1 22/30] memory: tegra20-emc: Support Tegra SoC device state syncing In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-23-digetx@gmail.com> Sync driver state using the Tegra SoC device state syncing API, telling to regulators voltage coupler that EMC state is ready for DVFS. This is required for enabling system-wide DVFS on Tegra20. Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- drivers/memory/tegra/tegra20-emc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c index 9946b957bb01..b1b0a2439689 100644 --- a/drivers/memory/tegra/tegra20-emc.c +++ b/drivers/memory/tegra/tegra20-emc.c @@ -1129,6 +1129,12 @@ static int tegra_emc_probe(struct platform_device *pdev) return err; } +static void tegra_emc_sync_state(struct device *dev) +{ + tegra_soc_device_sync_state(dev); + icc_sync_state(dev); +} + static const struct of_device_id tegra_emc_of_match[] = { { .compatible = "nvidia,tegra20-emc", }, {}, @@ -1141,7 +1147,7 @@ static struct platform_driver tegra_emc_driver = { .name = "tegra20-emc", .of_match_table = tegra_emc_of_match, .suppress_bind_attrs = true, - .sync_state = icc_sync_state, + .sync_state = tegra_emc_sync_state, }, }; module_platform_driver(tegra_emc_driver); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:20 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:20 +0300 Subject: [PATCH v1 23/30] memory: tegra30-emc: Support Tegra SoC device state syncing In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-24-digetx@gmail.com> Sync driver state using the Tegra SoC device state syncing API, telling to regulators voltage coupler that EMC state is ready for DVFS. This is required for enabling system-wide DVFS on Tegra30. Tested-by: Peter Geis Signed-off-by: Dmitry Osipenko --- drivers/memory/tegra/tegra30-emc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/memory/tegra/tegra30-emc.c b/drivers/memory/tegra/tegra30-emc.c index 6b20ce9f16af..dd7474065346 100644 --- a/drivers/memory/tegra/tegra30-emc.c +++ b/drivers/memory/tegra/tegra30-emc.c @@ -1666,6 +1666,12 @@ static int tegra_emc_resume(struct device *dev) return 0; } +static void tegra_emc_sync_state(struct device *dev) +{ + tegra_soc_device_sync_state(dev); + icc_sync_state(dev); +} + static const struct dev_pm_ops tegra_emc_pm_ops = { .suspend = tegra_emc_suspend, .resume = tegra_emc_resume, @@ -1684,7 +1690,7 @@ static struct platform_driver tegra_emc_driver = { .of_match_table = tegra_emc_of_match, .pm = &tegra_emc_pm_ops, .suppress_bind_attrs = true, - .sync_state = icc_sync_state, + .sync_state = tegra_emc_sync_state, }, }; module_platform_driver(tegra_emc_driver); -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:23 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:23 +0300 Subject: [PATCH v1 26/30] ARM: tegra: ventana: Add voltage supplies to DVFS-capable devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-27-digetx@gmail.com> Add voltage supplies to DVFS-capable devices in order to enable system-wide voltage scaling and allow CORE/RTC regulators to go lower. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20-ventana.dts | 65 +++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-ventana.dts b/arch/arm/boot/dts/tegra20-ventana.dts index b158771ac0b7..d5d90605e649 100644 --- a/arch/arm/boot/dts/tegra20-ventana.dts +++ b/arch/arm/boot/dts/tegra20-ventana.dts @@ -23,7 +23,19 @@ memory at 0 { }; host1x at 50000000 { + core-supply = <&vdd_core>; + + gr2d at 54140000 { + core-supply = <&vdd_core>; + }; + + gr3d at 54180000 { + core-supply = <&vdd_core>; + }; + dc at 54200000 { + core-supply = <&vdd_core>; + rgb { status = "okay"; @@ -31,11 +43,16 @@ rgb { }; }; + dc at 54240000 { + core-supply = <&vdd_core>; + }; + hdmi at 54280000 { status = "okay"; vdd-supply = <&hdmi_vdd_reg>; pll-supply = <&hdmi_pll_reg>; + core-supply = <&vdd_core>; nvidia,ddc-i2c-bus = <&hdmi_ddc>; nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7) @@ -43,6 +60,10 @@ hdmi at 54280000 { }; }; + vde at 6001a000 { + core-supply = <&vdd_core>; + }; + pinmux at 70000014 { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -419,18 +440,28 @@ sys_reg: sys { regulator-always-on; }; - sm0 { + vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&rtc_vdd &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-core-regulator; }; - sm1 { + vdd_cpu: sm1 { regulator-name = "vdd_sm1,vdd_cpu"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1000000>; + regulator-min-microvolt = <750000>; + regulator-max-microvolt = <1125000>; + regulator-coupled-with = <&vdd_core &rtc_vdd>; + regulator-coupled-max-spread = <550000 550000>; regulator-always-on; + regulator-boot-on; + + nvidia,tegra-cpu-regulator; }; sm2_reg: sm2 { @@ -449,10 +480,16 @@ ldo1 { regulator-always-on; }; - ldo2 { + rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1200000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-coupled-with = <&vdd_core &vdd_cpu>; + regulator-coupled-max-spread = <170000 550000>; + regulator-always-on; + regulator-boot-on; + + nvidia,tegra-rtc-regulator; }; ldo3 { @@ -526,8 +563,13 @@ pmc at 7000e400 { nvidia,sys-clock-req-active-high; }; + memory-controller at 7000f400 { + core-supply = <&vdd_core>; + }; + usb at c5000000 { status = "okay"; + core-supply = <&vdd_core>; }; usb-phy at c5000000 { @@ -538,6 +580,7 @@ usb at c5004000 { status = "okay"; nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>; + core-supply = <&vdd_core>; }; usb-phy at c5004000 { @@ -548,6 +591,7 @@ usb-phy at c5004000 { usb at c5008000 { status = "okay"; + core-supply = <&vdd_core>; }; usb-phy at c5008000 { @@ -559,6 +603,7 @@ mmc at c8000000 { power-gpios = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>; bus-width = <4>; keep-power-in-suspend; + core-supply = <&vdd_core>; }; mmc at c8000400 { @@ -567,12 +612,14 @@ mmc at c8000400 { wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>; power-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>; bus-width = <4>; + core-supply = <&vdd_core>; }; mmc at c8000600 { status = "okay"; bus-width = <8>; non-removable; + core-supply = <&vdd_core>; }; backlight: backlight { -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:22 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:22 +0300 Subject: [PATCH v1 25/30] ARM: tegra: Add OPP tables for Tegra30 peripheral devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-26-digetx@gmail.com> Add OPP tables for Tegra30 SoC devices. Signed-off-by: Dmitry Osipenko --- .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 415 ++++++++++++++++++ arch/arm/boot/dts/tegra30.dtsi | 13 + 2 files changed, 428 insertions(+) diff --git a/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi index cbe84d25e726..f8c522099dfe 100644 --- a/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra30-peripherals-opp.dtsi @@ -380,4 +380,419 @@ opp at 900000000 { opp-peak-kBps = <7200000>; }; }; + + vde_dvfs_opp_table: vde-opp-table { + compatible = "operating-points-v2"; + + opp at 228000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <228000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 247000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <247000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 275000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <275000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 304000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <304000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 332000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <332000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 352000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <352000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 380000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <380000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 400000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 416000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <416000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 437000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <437000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 484000000,1250 { + opp-microvolt = <1250000 1250000 1350000>; + opp-hz = /bits/ 64 <484000000>; + opp-supported-hw = <0x000C>; + }; + + opp at 520000000,1300 { + opp-microvolt = <1300000 1300000 1350000>; + opp-hz = /bits/ 64 <520000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 600000000,1350 { + opp-microvolt = <1350000 1350000 1350000>; + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x0004>; + }; + }; + + gr2d_dvfs_opp_table: gr2d-opp-table { + compatible = "operating-points-v2"; + + opp at 267000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <267000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 285000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <285000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 304000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <304000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 332000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <332000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 361000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <361000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 380000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <380000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 408000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <408000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 416000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <416000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 446000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <446000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 484000000,1250 { + opp-microvolt = <1250000 1250000 1350000>; + opp-hz = /bits/ 64 <484000000>; + opp-supported-hw = <0x000C>; + }; + + opp at 520000000,1300 { + opp-microvolt = <1300000 1300000 1350000>; + opp-hz = /bits/ 64 <520000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 600000000,1350 { + opp-microvolt = <1350000 1350000 1350000>; + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x0004>; + }; + }; + + gr3d_dvfs_opp_table: gr3d-opp-table { + compatible = "operating-points-v2"; + + opp at 234000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <234000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 247000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <247000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 285000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <285000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 304000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <304000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 332000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <332000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 361000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <361000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 380000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <380000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 408000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <408000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 416000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <416000000>; + opp-supported-hw = <0x0003>; + }; + + opp at 446000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <446000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 484000000,1250 { + opp-microvolt = <1250000 1250000 1350000>; + opp-hz = /bits/ 64 <484000000>; + opp-supported-hw = <0x000C>; + }; + + opp at 520000000,1300 { + opp-microvolt = <1300000 1300000 1350000>; + opp-hz = /bits/ 64 <520000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 600000000,1350 { + opp-microvolt = <1350000 1350000 1350000>; + opp-hz = /bits/ 64 <600000000>; + opp-supported-hw = <0x0004>; + }; + }; + + host1x_dvfs_opp_table: host1x-opp-table { + compatible = "operating-points-v2"; + + opp at 152000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <152000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 188000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <188000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 222000000,1100 { + opp-microvolt = <1100000 1100000 1350000>; + opp-hz = /bits/ 64 <222000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 242000000,1250 { + opp-microvolt = <1250000 1250000 1350000>; + opp-hz = /bits/ 64 <242000000>; + opp-supported-hw = <0x0008>; + }; + + opp at 254000000,1150 { + opp-microvolt = <1150000 1150000 1350000>; + opp-hz = /bits/ 64 <254000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 267000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <267000000>; + opp-supported-hw = <0x0007>; + }; + + opp at 300000000,1350 { + opp-microvolt = <1350000 1350000 1350000>; + opp-hz = /bits/ 64 <300000000>; + opp-supported-hw = <0x0004>; + }; + }; + + usbd_dvfs_opp_table: usbd-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + usb2_dvfs_opp_table: usb2-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + usb3_dvfs_opp_table: usb3-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + sdmmc1_dvfs_opp_table: sdmmc1-opp-table { + compatible = "operating-points-v2"; + + opp at 104000000 { + opp-microvolt = <950000 950000 1350000>; + opp-hz = /bits/ 64 <104000000>; + }; + + opp at 208000000 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <208000000>; + }; + }; + + sdmmc3_dvfs_opp_table: sdmmc3-opp-table { + compatible = "operating-points-v2"; + + opp at 104000000 { + opp-microvolt = <950000 950000 1350000>; + opp-hz = /bits/ 64 <104000000>; + }; + + opp at 208000000 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <208000000>; + }; + }; + + hdmi_dvfs_opp_table: hdmi-opp-table { + compatible = "operating-points-v2"; + + opp at 148500000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <148500000>; + }; + }; + + pwm_dvfs_opp_table: pwm-opp-table { + compatible = "operating-points-v2"; + + opp at 408000000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <408000000>; + }; + }; + + dc0_dvfs_opp_table: dc0-opp-table { + compatible = "operating-points-v2"; + + opp at 120000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <120000000>; + opp-supported-hw = <0x0009>; + }; + + opp at 155000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <155000000>; + opp-supported-hw = <0x0006>; + }; + + opp at 190000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <190000000>; + opp-supported-hw = <0x0009>; + }; + + opp at 268000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <268000000>; + opp-supported-hw = <0x0006>; + }; + }; + + dc1_dvfs_opp_table: dc1-opp-table { + compatible = "operating-points-v2"; + + opp at 120000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <120000000>; + opp-supported-hw = <0x0009>; + }; + + opp at 155000000,1000 { + opp-microvolt = <1000000 1000000 1350000>; + opp-hz = /bits/ 64 <155000000>; + opp-supported-hw = <0x0006>; + }; + + opp at 190000000,1200 { + opp-microvolt = <1200000 1200000 1350000>; + opp-hz = /bits/ 64 <190000000>; + opp-supported-hw = <0x0009>; + }; + + opp at 268000000,1050 { + opp-microvolt = <1050000 1050000 1350000>; + opp-hz = /bits/ 64 <268000000>; + opp-supported-hw = <0x0006>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 44a6dbba7081..c387d46f737c 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -123,6 +123,7 @@ host1x at 50000000 { resets = <&tegra_car 28>; reset-names = "host1x"; iommus = <&mc TEGRA_SWGROUP_HC>; + operating-points-v2 = <&host1x_dvfs_opp_table>; #address-cells = <1>; #size-cells = <1>; @@ -180,6 +181,7 @@ gr2d at 54140000 { clocks = <&tegra_car TEGRA30_CLK_GR2D>; resets = <&tegra_car 21>; reset-names = "2d"; + operating-points-v2 = <&gr2d_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_G2>; }; @@ -193,6 +195,7 @@ gr3d at 54180000 { resets = <&tegra_car 24>, <&tegra_car 98>; reset-names = "3d", "3d2"; + operating-points-v2 = <&gr3d_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_NV>, <&mc TEGRA_SWGROUP_NV2>; @@ -207,6 +210,7 @@ dc at 54200000 { clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; + operating-points-v2 = <&dc0_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_DC>; @@ -237,6 +241,7 @@ dc at 54240000 { clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; + operating-points-v2 = <&dc1_dvfs_opp_table>; iommus = <&mc TEGRA_SWGROUP_DCB>; @@ -268,6 +273,7 @@ hdmi at 54280000 { resets = <&tegra_car 51>; reset-names = "hdmi"; status = "disabled"; + operating-points-v2 = <&hdmi_dvfs_opp_table>; }; tvo at 542c0000 { @@ -466,6 +472,7 @@ vde at 6001a000 { reset-names = "vde", "mc"; resets = <&tegra_car 61>, <&mc TEGRA30_MC_RESET_VDE>; iommus = <&mc TEGRA_SWGROUP_VDE>; + operating-points-v2 = <&vde_dvfs_opp_table>; }; apbmisc at 70000800 { @@ -574,6 +581,7 @@ pwm: pwm at 7000a000 { resets = <&tegra_car 17>; reset-names = "pwm"; status = "disabled"; + operating-points-v2 = <&pwm_dvfs_opp_table>; }; rtc at 7000e000 { @@ -906,6 +914,7 @@ mmc at 78000000 { resets = <&tegra_car 14>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc1_dvfs_opp_table>; }; mmc at 78000200 { @@ -928,6 +937,7 @@ mmc at 78000400 { resets = <&tegra_car 69>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc3_dvfs_opp_table>; }; mmc at 78000600 { @@ -952,6 +962,7 @@ usb at 7d000000 { nvidia,needs-double-reset; nvidia,phy = <&phy1>; status = "disabled"; + operating-points-v2 = <&usbd_dvfs_opp_table>; }; phy1: usb-phy at 7d000000 { @@ -991,6 +1002,7 @@ usb at 7d004000 { reset-names = "usb"; nvidia,phy = <&phy2>; status = "disabled"; + operating-points-v2 = <&usb2_dvfs_opp_table>; }; phy2: usb-phy at 7d004000 { @@ -1029,6 +1041,7 @@ usb at 7d008000 { reset-names = "usb"; nvidia,phy = <&phy3>; status = "disabled"; + operating-points-v2 = <&usb3_dvfs_opp_table>; }; phy3: usb-phy at 7d008000 { -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:24 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:24 +0300 Subject: [PATCH v1 27/30] ARM: tegra: paz00: Add voltage supplies to DVFS-capable devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-28-digetx@gmail.com> Add voltage supplies to DVFS-capable devices in order to enable system-wide voltage scaling and allow CORE/RTC regulators to go lower. Tested-by: Nicolas Chauvet Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra20-paz00.dts | 40 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 52a81d888424..d497eb149fba 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -26,7 +26,19 @@ memory at 0 { }; host1x at 50000000 { + core-supply = <&core_vdd_reg>; + + gr2d at 54140000 { + core-supply = <&core_vdd_reg>; + }; + + gr3d at 54180000 { + core-supply = <&core_vdd_reg>; + }; + dc at 54200000 { + core-supply = <&core_vdd_reg>; + rgb { status = "okay"; @@ -34,11 +46,16 @@ rgb { }; }; + dc at 54240000 { + core-supply = <&core_vdd_reg>; + }; + hdmi at 54280000 { status = "okay"; vdd-supply = <&hdmi_vdd_reg>; pll-supply = <&hdmi_pll_reg>; + core-supply = <&core_vdd_reg>; nvidia,ddc-i2c-bus = <&hdmi_ddc>; nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7) @@ -46,6 +63,10 @@ hdmi at 54280000 { }; }; + vde at 6001a000 { + core-supply = <&core_vdd_reg>; + }; + pinmux at 70000014 { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -389,10 +410,10 @@ sys_reg: sys { core_vdd_reg: sm0 { regulator-name = "+1.2vs_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1225000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; regulator-coupled-with = <&rtc_vdd_reg &cpu_vdd_reg>; - regulator-coupled-max-spread = <170000 450000>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; nvidia,tegra-core-regulator; @@ -403,7 +424,7 @@ cpu_vdd_reg: sm1 { regulator-min-microvolt = <750000>; regulator-max-microvolt = <1100000>; regulator-coupled-with = <&core_vdd_reg &rtc_vdd_reg>; - regulator-coupled-max-spread = <450000 450000>; + regulator-coupled-max-spread = <550000 550000>; regulator-always-on; nvidia,tegra-cpu-regulator; @@ -427,10 +448,10 @@ ldo1 { rtc_vdd_reg: ldo2 { regulator-name = "+1.2vs_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; - regulator-max-microvolt = <1225000>; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; regulator-coupled-with = <&core_vdd_reg &cpu_vdd_reg>; - regulator-coupled-max-spread = <170000 450000>; + regulator-coupled-max-spread = <170000 550000>; regulator-always-on; nvidia,tegra-rtc-regulator; @@ -519,6 +540,7 @@ usb at c5000000 { compatible = "nvidia,tegra20-udc"; status = "okay"; dr_mode = "peripheral"; + core-supply = <&core_vdd_reg>; }; usb-phy at c5000000 { @@ -529,6 +551,7 @@ usb at c5004000 { status = "okay"; nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 0) GPIO_ACTIVE_LOW>; + core-supply = <&core_vdd_reg>; }; usb-phy at c5004000 { @@ -539,6 +562,7 @@ usb-phy at c5004000 { usb at c5008000 { status = "okay"; + core-supply = <&core_vdd_reg>; }; usb-phy at c5008000 { @@ -551,12 +575,14 @@ mmc at c8000000 { wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>; power-gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>; bus-width = <4>; + core-supply = <&core_vdd_reg>; }; mmc at c8000600 { status = "okay"; bus-width = <8>; non-removable; + core-supply = <&core_vdd_reg>; }; backlight: backlight { -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:25 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:25 +0300 Subject: [PATCH v1 28/30] ARM: tegra: acer-a500: Add voltage supplies to DVFS-capable devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-29-digetx@gmail.com> Add voltage supplies to DVFS-capable devices in order to enable system-wide voltage scaling and allow CORE/RTC regulators to go lower. Signed-off-by: Dmitry Osipenko --- .../boot/dts/tegra20-acer-a500-picasso.dts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts index b4ed88802387..5ab6872cd84c 100644 --- a/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts +++ b/arch/arm/boot/dts/tegra20-acer-a500-picasso.dts @@ -60,7 +60,19 @@ linux,cma at 30000000 { }; host1x at 50000000 { + core-supply = <&vdd_core>; + + gr2d at 54140000 { + core-supply = <&vdd_core>; + }; + + gr3d at 54180000 { + core-supply = <&vdd_core>; + }; + dc at 54200000 { + core-supply = <&vdd_core>; + rgb { status = "okay"; @@ -73,12 +85,17 @@ lcd_output: endpoint { }; }; + dc at 54240000 { + core-supply = <&vdd_core>; + }; + hdmi at 54280000 { status = "okay"; vdd-supply = <&hdmi_vdd_reg>; pll-supply = <&hdmi_pll_reg>; hdmi-supply = <&vdd_5v0_sys>; + core-supply = <&vdd_core>; nvidia,ddc-i2c-bus = <&hdmi_ddc>; nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7) @@ -86,6 +103,10 @@ hdmi at 54280000 { }; }; + vde at 6001a000 { + core-supply = <&vdd_core>; + }; + pinmux at 70000014 { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -565,7 +586,7 @@ sys_reg: sys { vdd_core: sm0 { regulator-name = "vdd_sm0,vdd_core"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&rtc_vdd &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>; @@ -606,7 +627,7 @@ ldo1 { rtc_vdd: ldo2 { regulator-name = "vdd_ldo2,vdd_rtc"; - regulator-min-microvolt = <1200000>; + regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; regulator-coupled-with = <&vdd_core &vdd_cpu>; regulator-coupled-max-spread = <170000 550000>; @@ -696,6 +717,7 @@ usb at c5000000 { compatible = "nvidia,tegra20-udc"; status = "okay"; dr_mode = "peripheral"; + core-supply = <&vdd_core>; }; usb-phy at c5000000 { @@ -709,6 +731,7 @@ usb-phy at c5000000 { usb at c5008000 { status = "okay"; + core-supply = <&vdd_core>; }; usb-phy at c5008000 { @@ -746,6 +769,7 @@ sdmmc1: mmc at c8000000 { non-removable; mmc-pwrseq = <&brcm_wifi_pwrseq>; + core-supply = <&vdd_core>; vmmc-supply = <&vdd_3v3_sys>; vqmmc-supply = <&vdd_3v3_sys>; @@ -764,6 +788,7 @@ sdmmc3: mmc at c8000400 { bus-width = <4>; cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>; power-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>; + core-supply = <&vdd_core>; vmmc-supply = <&vdd_3v3_sys>; vqmmc-supply = <&vdd_3v3_sys>; }; @@ -771,6 +796,7 @@ sdmmc3: mmc at c8000400 { sdmmc4: mmc at c8000600 { status = "okay"; bus-width = <8>; + core-supply = <&vdd_core>; vmmc-supply = <&vcore_emmc>; vqmmc-supply = <&vdd_3v3_sys>; non-removable; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:26 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:26 +0300 Subject: [PATCH v1 29/30] ARM: tegra: cardhu-a04: Add voltage supplies to DVFS-capable devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-30-digetx@gmail.com> Add voltage supplies to DVFS-capable devices in order to enable system-wide voltage scaling. Signed-off-by: Dmitry Osipenko --- arch/arm/boot/dts/tegra30-cardhu-a04.dts | 44 ++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/arch/arm/boot/dts/tegra30-cardhu-a04.dts b/arch/arm/boot/dts/tegra30-cardhu-a04.dts index c1c0ca628af1..7149e5594537 100644 --- a/arch/arm/boot/dts/tegra30-cardhu-a04.dts +++ b/arch/arm/boot/dts/tegra30-cardhu-a04.dts @@ -93,6 +93,34 @@ vdd_bl2_reg: regulator at 106 { gpio = <&gpio TEGRA_GPIO(DD, 0) GPIO_ACTIVE_HIGH>; }; + host1x at 50000000 { + core-supply = <&vddcore_reg>; + + gr2d at 54140000 { + core-supply = <&vddcore_reg>; + }; + + gr3d at 54180000 { + core-supply = <&vddcore_reg>; + }; + + dc at 54200000 { + core-supply = <&vddcore_reg>; + }; + + dc at 54240000 { + core-supply = <&vddcore_reg>; + }; + }; + + vde at 6001a000 { + core-supply = <&vddcore_reg>; + }; + + pwm: pwm at 7000a000 { + core-supply = <&vddcore_reg>; + }; + i2c at 7000d000 { pmic: tps65911 at 2d { regulators { @@ -117,6 +145,22 @@ vddcore_reg: tps62361 at 60 { }; }; + memory-controller at 7000f400 { + core-supply = <&vddcore_reg>; + }; + + mmc at 78000000 { + core-supply = <&vddcore_reg>; + }; + + mmc at 78000600 { + core-supply = <&vddcore_reg>; + }; + + usb at 7d008000 { + core-supply = <&vddcore_reg>; + }; + cpus { cpu0: cpu at 0 { cpu-supply = <&vddctrl_reg>; -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:27 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:27 +0300 Subject: [PATCH v1 30/30] ARM: tegra: nexus7: Add voltage supplies to DVFS-capable devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-31-digetx@gmail.com> Add voltage supplies to DVFS-capable devices in order to enable system-wide voltage scaling. Signed-off-by: Dmitry Osipenko --- .../tegra30-asus-nexus7-grouper-common.dtsi | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi index 261e266c61d8..2b405872ad2d 100644 --- a/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi +++ b/arch/arm/boot/dts/tegra30-asus-nexus7-grouper-common.dtsi @@ -60,7 +60,19 @@ trustzone at bfe00000 { }; host1x at 50000000 { + core-supply = <&vdd_core>; + + gr2d at 54140000 { + core-supply = <&vdd_core>; + }; + + gr3d at 54180000 { + core-supply = <&vdd_core>; + }; + dc at 54200000 { + core-supply = <&vdd_core>; + rgb { status = "okay"; @@ -72,6 +84,10 @@ lcd_output: endpoint { }; }; }; + + dc at 54240000 { + core-supply = <&vdd_core>; + }; }; gpio at 6000d000 { @@ -90,6 +106,10 @@ init-low-power-mode { }; }; + vde at 6001a000 { + core-supply = <&vdd_core>; + }; + pinmux at 70000868 { pinctrl-names = "default"; pinctrl-0 = <&state_default>; @@ -835,6 +855,7 @@ bluetooth { pwm: pwm at 7000a000 { status = "okay"; + core-supply = <&vdd_core>; }; i2c at 7000c400 { @@ -994,6 +1015,7 @@ sdmmc3: mmc at 78000400 { mmc-pwrseq = <&brcm_wifi_pwrseq>; vmmc-supply = <&vdd_3v3_sys>; + core-supply = <&vdd_core>; vqmmc-supply = <&vdd_1v8>; /* Azurewave AW-NH665 BCM4330 */ @@ -1018,6 +1040,7 @@ usb at 7d000000 { compatible = "nvidia,tegra30-udc"; status = "okay"; dr_mode = "peripheral"; + core-supply = <&vdd_core>; }; usb-phy at 7d000000 { -- 2.27.0 From digetx at gmail.com Wed Nov 4 23:44:21 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 02:44:21 +0300 Subject: [PATCH v1 24/30] ARM: tegra: Add OPP tables for Tegra20 peripheral devices In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201104234427.26477-25-digetx@gmail.com> Add OPP tables for Tegra20 SoC devices. Signed-off-by: Dmitry Osipenko --- .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 386 ++++++++++++++++++ arch/arm/boot/dts/tegra20.dtsi | 14 + 2 files changed, 400 insertions(+) diff --git a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi index 25b1ba73951e..792dc79d32c5 100644 --- a/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi +++ b/arch/arm/boot/dts/tegra20-peripherals-opp.dtsi @@ -89,4 +89,390 @@ opp at 760000000 { opp-hz = /bits/ 64 <760000000>; }; }; + + vde_dvfs_opp_table: vde-opp-table { + compatible = "operating-points-v2"; + + opp at 95000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <95000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 123500000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <123500000>; + opp-supported-hw = <0x0001>; + }; + + opp at 123500000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <123500000>; + opp-supported-hw = <0x0002>; + }; + + opp at 152000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <152000000>; + opp-supported-hw = <0x0002>; + }; + + opp at 152000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <152000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 171000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <171000000>; + opp-supported-hw = <0x0008>; + }; + + opp at 209000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <209000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 209000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <209000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 218500000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <218500000>; + opp-supported-hw = <0x0008>; + }; + + opp at 237500000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <237500000>; + opp-supported-hw = <0x0002>; + }; + + opp at 275500000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <275500000>; + opp-supported-hw = <0x0001>; + }; + + opp at 285000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <285000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 300000000,1275 { + opp-microvolt = <1275000 1275000 1300000>; + opp-hz = /bits/ 64 <300000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 300000000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <300000000>; + opp-supported-hw = <0x0006>; + }; + + opp at 300000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <300000000>; + opp-supported-hw = <0x0008>; + }; + }; + + gr2d_dvfs_opp_table: gr2d-opp-table { + compatible = "operating-points-v2"; + + opp at 133000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <133000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 171000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <171000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 247000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <247000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 300000000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <300000000>; + opp-supported-hw = <0x000F>; + }; + }; + + gr3d_dvfs_opp_table: gr3d-opp-table { + compatible = "operating-points-v2"; + + opp at 114000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <114000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 161500000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <161500000>; + opp-supported-hw = <0x0001>; + }; + + opp at 161500000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <161500000>; + opp-supported-hw = <0x0002>; + }; + + opp at 209000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <209000000>; + opp-supported-hw = <0x0002>; + }; + + opp at 218500000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <218500000>; + opp-supported-hw = <0x0004>; + }; + + opp at 247000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <247000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 247000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <247000000>; + opp-supported-hw = <0x0008>; + }; + + opp at 256500000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <256500000>; + opp-supported-hw = <0x0004>; + }; + + opp at 285000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <285000000>; + opp-supported-hw = <0x0002>; + }; + + opp at 285000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <285000000>; + opp-supported-hw = <0x0008>; + }; + + opp at 304000000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <304000000>; + opp-supported-hw = <0x0001>; + }; + + opp at 323000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <323000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 333500000,1275 { + opp-microvolt = <1275000 1275000 1300000>; + opp-hz = /bits/ 64 <333500000>; + opp-supported-hw = <0x0001>; + }; + + opp at 333500000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <333500000>; + opp-supported-hw = <0x0002>; + }; + + opp at 351500000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <351500000>; + opp-supported-hw = <0x0008>; + }; + + opp at 361000000,1275 { + opp-microvolt = <1275000 1275000 1300000>; + opp-hz = /bits/ 64 <361000000>; + opp-supported-hw = <0x0002>; + }; + + opp at 380000000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <380000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 400000000,1275 { + opp-microvolt = <1275000 1275000 1300000>; + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x0004>; + }; + + opp at 400000000,1200 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <400000000>; + opp-supported-hw = <0x0008>; + }; + }; + + host1x_dvfs_opp_table: host1x-opp-table { + compatible = "operating-points-v2"; + + opp at 104500000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <104500000>; + opp-supported-hw = <0x000F>; + }; + + opp at 133000000,1000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <133000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 166000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <166000000>; + opp-supported-hw = <0x000F>; + }; + }; + + usbd_dvfs_opp_table: usbd-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + usb2_dvfs_opp_table: usb2-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + usb3_dvfs_opp_table: usb3-opp-table { + compatible = "operating-points-v2"; + + opp at 480000000 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <480000000>; + }; + }; + + sdmmc1_dvfs_opp_table: sdmmc1-opp-table { + compatible = "operating-points-v2"; + + opp at 44000000 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <44000000>; + }; + + opp at 52000000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <52000000>; + }; + }; + + sdmmc2_dvfs_opp_table: sdmmc2-opp-table { + compatible = "operating-points-v2"; + + opp at 44000000 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <44000000>; + }; + + opp at 52000000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <52000000>; + }; + }; + + sdmmc3_dvfs_opp_table: sdmmc3-opp-table { + compatible = "operating-points-v2"; + + opp at 44000000 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <44000000>; + }; + + opp at 52000000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <52000000>; + }; + }; + + sdmmc4_dvfs_opp_table: sdmmc4-opp-table { + compatible = "operating-points-v2"; + + opp at 44000000 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <44000000>; + }; + + opp at 52000000 { + opp-microvolt = <1000000 1000000 1300000>; + opp-hz = /bits/ 64 <52000000>; + }; + }; + + hdmi_dvfs_opp_table: hdmi-opp-table { + compatible = "operating-points-v2"; + + opp at 148500000 { + opp-microvolt = <1200000 1200000 1300000>; + opp-hz = /bits/ 64 <148500000>; + }; + }; + + dc0_dvfs_opp_table: dc0-opp-table { + compatible = "operating-points-v2"; + + opp at 158000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <158000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 190000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <190000000>; + opp-supported-hw = <0x000F>; + }; + }; + + dc1_dvfs_opp_table: dc1-opp-table { + compatible = "operating-points-v2"; + + opp at 158000000,950 { + opp-microvolt = <950000 950000 1300000>; + opp-hz = /bits/ 64 <158000000>; + opp-supported-hw = <0x000F>; + }; + + opp at 190000000,1100 { + opp-microvolt = <1100000 1100000 1300000>; + opp-hz = /bits/ 64 <190000000>; + opp-supported-hw = <0x000F>; + }; + }; }; diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index 6ce498178105..317bdf75ff6c 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -42,6 +42,7 @@ host1x at 50000000 { clock-names = "host1x"; resets = <&tegra_car 28>; reset-names = "host1x"; + operating-points-v2 = <&host1x_dvfs_opp_table>; #address-cells = <1>; #size-cells = <1>; @@ -91,6 +92,7 @@ gr2d at 54140000 { clocks = <&tegra_car TEGRA20_CLK_GR2D>; resets = <&tegra_car 21>; reset-names = "2d"; + operating-points-v2 = <&gr2d_dvfs_opp_table>; }; gr3d at 54180000 { @@ -99,6 +101,7 @@ gr3d at 54180000 { clocks = <&tegra_car TEGRA20_CLK_GR3D>; resets = <&tegra_car 24>; reset-names = "3d"; + operating-points-v2 = <&gr3d_dvfs_opp_table>; }; dc at 54200000 { @@ -110,6 +113,7 @@ dc at 54200000 { clock-names = "dc", "parent"; resets = <&tegra_car 27>; reset-names = "dc"; + operating-points-v2 = <&dc0_dvfs_opp_table>; nvidia,head = <0>; @@ -138,6 +142,7 @@ dc at 54240000 { clock-names = "dc", "parent"; resets = <&tegra_car 26>; reset-names = "dc"; + operating-points-v2 = <&dc1_dvfs_opp_table>; nvidia,head = <1>; @@ -167,6 +172,7 @@ hdmi at 54280000 { resets = <&tegra_car 51>; reset-names = "hdmi"; status = "disabled"; + operating-points-v2 = <&hdmi_dvfs_opp_table>; }; tvo at 542c0000 { @@ -319,6 +325,7 @@ vde at 6001a000 { clocks = <&tegra_car TEGRA20_CLK_VDE>; reset-names = "vde", "mc"; resets = <&tegra_car 61>, <&mc TEGRA20_MC_RESET_VDE>; + operating-points-v2 = <&vde_dvfs_opp_table>; }; apbmisc at 70000800 { @@ -755,6 +762,7 @@ usb at c5000000 { nvidia,needs-double-reset; nvidia,phy = <&phy1>; status = "disabled"; + operating-points-v2 = <&usbd_dvfs_opp_table>; }; phy1: usb-phy at c5000000 { @@ -792,6 +800,7 @@ usb at c5004000 { reset-names = "usb"; nvidia,phy = <&phy2>; status = "disabled"; + operating-points-v2 = <&usb2_dvfs_opp_table>; }; phy2: usb-phy at c5004000 { @@ -818,6 +827,7 @@ usb at c5008000 { reset-names = "usb"; nvidia,phy = <&phy3>; status = "disabled"; + operating-points-v2 = <&usb3_dvfs_opp_table>; }; phy3: usb-phy at c5008000 { @@ -852,6 +862,7 @@ mmc at c8000000 { resets = <&tegra_car 14>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc1_dvfs_opp_table>; }; mmc at c8000200 { @@ -863,6 +874,7 @@ mmc at c8000200 { resets = <&tegra_car 9>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc2_dvfs_opp_table>; }; mmc at c8000400 { @@ -874,6 +886,7 @@ mmc at c8000400 { resets = <&tegra_car 69>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc3_dvfs_opp_table>; }; mmc at c8000600 { @@ -885,6 +898,7 @@ mmc at c8000600 { resets = <&tegra_car 15>; reset-names = "sdhci"; status = "disabled"; + operating-points-v2 = <&sdmmc4_dvfs_opp_table>; }; cpus { -- 2.27.0 From mirq-linux at rere.qmqm.pl Thu Nov 5 01:45:02 2020 From: mirq-linux at rere.qmqm.pl (=?iso-8859-2?Q?Micha=B3_Miros=B3aw?=) Date: Thu, 5 Nov 2020 02:45:02 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201105014502.GB17266@qmqm.qmqm.pl> On Thu, Nov 05, 2020 at 02:43:57AM +0300, Dmitry Osipenko wrote: > Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces > power consumption and heating of the Tegra chips. Tegra SoC has multiple > hardware units which belong to a core power domain of the SoC and share > the core voltage. The voltage must be selected in accordance to a minimum > requirement of every core hardware unit. [...] Just looked briefly through the series - it looks like there is a lot of code duplication in *_init_opp_table() functions. Could this be made more generic / data-driven? Best Regards Micha? Miros?aw From ross.schm.dev at gmail.com Thu Nov 5 03:47:47 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:47 -0600 Subject: [PATCH 2/9] staging: rtl8723bs: use %pM format for MAC addresses In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-2-ross.schm.dev@gmail.com> Use %pM format instead of custom printing code. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/hal/sdio_halinit.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/sdio_halinit.c b/drivers/staging/rtl8723bs/hal/sdio_halinit.c index e42d8c18e1ae..08abfb8ec4c7 100644 --- a/drivers/staging/rtl8723bs/hal/sdio_halinit.c +++ b/drivers/staging/rtl8723bs/hal/sdio_halinit.c @@ -1231,19 +1231,8 @@ static void Hal_EfuseParseMACAddr_8723BS( } /* NicIFSetMacAddress(padapter, padapter->PermanentAddress); */ - RT_TRACE( - _module_hci_hal_init_c_, - _drv_notice_, - ( - "Hal_EfuseParseMACAddr_8723BS: Permanent Address = %02x-%02x-%02x-%02x-%02x-%02x\n", - pEEPROM->mac_addr[0], - pEEPROM->mac_addr[1], - pEEPROM->mac_addr[2], - pEEPROM->mac_addr[3], - pEEPROM->mac_addr[4], - pEEPROM->mac_addr[5] - ) - ); + RT_TRACE(_module_hci_hal_init_c_, _drv_notice_, + ("Hal_EfuseParseMACAddr_8723BS: Permanent Address = %pM\n", pEEPROM->mac_addr)); } static void Hal_EfuseParseBoardType_8723BS( -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:46 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:46 -0600 Subject: [PATCH 1/9] staging: rtl8723bs: remove MAC_FMT macro Message-ID: <20201105034754.12383-1-ross.schm.dev@gmail.com> Remove unnecessary macro for %pM and call it directly. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_ap.c | 39 +++++---------- drivers/staging/rtl8723bs/core/rtw_cmd.c | 2 +- .../staging/rtl8723bs/core/rtw_ieee80211.c | 2 +- .../staging/rtl8723bs/core/rtw_ioctl_set.c | 4 +- drivers/staging/rtl8723bs/core/rtw_mlme.c | 24 +++++----- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 47 +++++++++---------- drivers/staging/rtl8723bs/core/rtw_recv.c | 22 ++++----- .../staging/rtl8723bs/core/rtw_wlan_util.c | 6 +-- drivers/staging/rtl8723bs/core/rtw_xmit.c | 10 ++-- drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c | 4 +- drivers/staging/rtl8723bs/include/ieee80211.h | 1 - .../staging/rtl8723bs/include/osdep_service.h | 3 -- .../staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 14 +++--- .../staging/rtl8723bs/os_dep/ioctl_linux.c | 16 +++---- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 8 ++-- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 2 +- 16 files changed, 93 insertions(+), 111 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index afe7023a9e8e..d9a55bee83a3 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -182,7 +182,7 @@ u8 chk_sta_is_alive(struct sta_info *psta) { #ifdef DBG_EXPIRATION_CHK DBG_871X( - "sta:"MAC_FMT", rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" + "sta:%pM, rssi:%d, rx:"STA_PKTS_FMT", expire_to:%u, %s%ssq_len:%u\n" , MAC_ARG(psta->hwaddr) , psta->rssi_stat.UndecoratedSmoothedPWDB /* STA_RX_PKTS_ARG(psta) */ @@ -297,7 +297,7 @@ void expire_timeout_chk(struct adapter *padapter) psta->expire_to = pstapriv->expire_to; psta->state |= WIFI_STA_ALIVE_CHK_STATE; - /* DBG_871X("alive chk, sta:" MAC_FMT " is at ps mode!\n", MAC_ARG(psta->hwaddr)); */ + /* DBG_871X("alive chk, sta:%pM is at ps mode!\n", MAC_ARG(psta->hwaddr)); */ /* to update bcn with tim_bitmap for this station */ pstapriv->tim_bitmap |= BIT(psta->aid); @@ -319,7 +319,7 @@ void expire_timeout_chk(struct adapter *padapter) list_del_init(&psta->asoc_list); pstapriv->asoc_list_cnt--; DBG_871X( - "asoc expire "MAC_FMT", state = 0x%x\n", + "asoc expire %pM, state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state ); @@ -332,7 +332,7 @@ void expire_timeout_chk(struct adapter *padapter) ) / 2) ) { DBG_871X( - "%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", + "%s sta:%pM, sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__, MAC_ARG(psta->hwaddr), psta->sleepq_len, @@ -372,7 +372,7 @@ void expire_timeout_chk(struct adapter *padapter) psta->keep_alive_trycnt++; if (ret == _SUCCESS) { DBG_871X( - "asoc check, sta(" MAC_FMT ") is alive\n", + "asoc check, sta(%pM) is alive\n", MAC_ARG(psta->hwaddr) ); psta->expire_to = pstapriv->expire_to; @@ -387,10 +387,8 @@ void expire_timeout_chk(struct adapter *padapter) } psta->keep_alive_trycnt = 0; - DBG_871X( - "asoc expire "MAC_FMT", state = 0x%x\n", - MAC_ARG(psta->hwaddr), - psta->state); + DBG_871X("asoc expire %pM, state = 0x%x\n", MAC_ARG(psta->hwaddr), + psta->state); spin_lock_bh(&pstapriv->asoc_list_lock); if (list_empty(&psta->asoc_list) == false) { list_del_init(&psta->asoc_list); @@ -1335,12 +1333,7 @@ int rtw_acl_add_sta(struct adapter *padapter, u8 *addr) struct wlan_acl_pool *pacl_list = &pstapriv->acl_list; struct __queue *pacl_node_q = &pacl_list->acl_node_q; - DBG_871X( - "%s(acl_num =%d) =" MAC_FMT "\n", - __func__, - pacl_list->num, - MAC_ARG(addr) - ); + DBG_871X("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, MAC_ARG(addr)); if ((NUM_ACL - 1) < pacl_list->num) return (-1); @@ -1404,12 +1397,7 @@ void rtw_acl_remove_sta(struct adapter *padapter, u8 *addr) struct __queue *pacl_node_q = &pacl_list->acl_node_q; u8 baddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; /* Baddr is used for clearing acl_list */ - DBG_871X( - "%s(acl_num =%d) =" MAC_FMT "\n", - __func__, - pacl_list->num, - MAC_ARG(addr) - ); + DBG_871X("%s(acl_num =%d) =%pM\n", __func__, pacl_list->num, MAC_ARG(addr)); spin_lock_bh(&(pacl_node_q->lock)); @@ -2021,7 +2009,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) if (psta->flags & WLAN_STA_HT) { u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info); - DBG_871X("HT: STA " MAC_FMT " HT Capabilities " + DBG_871X("HT: STA %pM HT Capabilities " "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab); if (psta->no_ht_set) { @@ -2034,7 +2022,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) psta->no_ht_gf_set = 1; pmlmepriv->num_sta_ht_no_gf++; } - DBG_871X("%s STA " MAC_FMT " - no " + DBG_871X("%s STA %pM - no " "greenfield, num of non-gf stations %d\n", __func__, MAC_ARG(psta->hwaddr), pmlmepriv->num_sta_ht_no_gf); @@ -2045,7 +2033,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) psta->ht_20mhz_set = 1; pmlmepriv->num_sta_ht_20mhz++; } - DBG_871X("%s STA " MAC_FMT " - 20 MHz HT, " + DBG_871X("%s STA %pM - 20 MHz HT, " "num of 20MHz HT STAs %d\n", __func__, MAC_ARG(psta->hwaddr), pmlmepriv->num_sta_ht_20mhz); @@ -2057,8 +2045,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) pmlmepriv->num_sta_no_ht++; } if (pmlmepriv->htpriv.ht_option == true) { - DBG_871X("%s STA " MAC_FMT - " - no HT, num of non-HT stations %d\n", + DBG_871X("%s STA %pM - no HT, num of non-HT stations %d\n", __func__, MAC_ARG(psta->hwaddr), pmlmepriv->num_sta_no_ht); } diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 4cf09d947d32..4e11cd97cc01 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -1024,7 +1024,7 @@ u8 rtw_clearstakey_cmd(struct adapter *padapter, struct sta_info *sta, u8 enqueu if (!enqueue) { while ((cam_id = rtw_camid_search(padapter, sta->hwaddr, -1)) >= 0) { - DBG_871X_LEVEL(_drv_always_, "clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(sta->hwaddr), cam_id); + DBG_871X_LEVEL(_drv_always_, "clear key for addr:%pM, camid:%d\n", MAC_ARG(sta->hwaddr), cam_id); clear_cam_entry(padapter, cam_id); rtw_camid_free(padapter, cam_id); } diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index c43cca4a3828..066dd9cbb60d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -1127,7 +1127,7 @@ void rtw_macaddr_cfg(struct device *dev, u8 *mac_addr) } } - DBG_871X("rtw_macaddr_cfg MAC Address = "MAC_FMT"\n", MAC_ARG(mac_addr)); + DBG_871X("rtw_macaddr_cfg MAC Address = %pM\n", MAC_ARG(mac_addr)); } static int rtw_get_cipher_info(struct wlan_network *pnetwork) diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c index 8b5f6a66bfb8..d44b33e7a0a9 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c @@ -189,8 +189,8 @@ u8 rtw_set_802_11_bssid(struct adapter *padapter, u8 *bssid) goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */ } else { RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("Set BSSID not the same bssid\n")); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid ="MAC_FMT"\n", MAC_ARG(bssid))); - RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid ="MAC_FMT"\n", MAC_ARG(pmlmepriv->cur_network.network.MacAddress))); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("set_bssid =%pM\n", MAC_ARG(bssid))); + RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, ("cur_bssid =%pM\n", MAC_ARG(pmlmepriv->cur_network.network.MacAddress))); rtw_disassoc_cmd(padapter, 0, true); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index 7f53ba541d04..b5226a517b91 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -494,7 +494,7 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT", ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" + DBG_871X(FUNC_ADPT_FMT" %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n" , FUNC_ADPT_ARG(padapter) , src->Ssid.Ssid, MAC_ARG(src->MacAddress), src->Configuration.DSConfig , ss_ori, sq_ori, rssi_ori @@ -539,7 +539,7 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src, #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) && 1 if (strcmp(dst->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X(FUNC_ADPT_FMT" %s("MAC_FMT"), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" + DBG_871X(FUNC_ADPT_FMT" %s(%pM), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n" , FUNC_ADPT_ARG(padapter) , dst->Ssid.Ssid, MAC_ARG(dst->MacAddress), dst->PhyInfo.SignalStrength, dst->PhyInfo.SignalQuality, dst->Rssi); } @@ -986,7 +986,7 @@ void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue) struct debug_priv *pdbgpriv = &psdpriv->drv_dbg; RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources\n")); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress ="MAC_FMT" ssid =%s\n", + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress =%pM ssid =%s\n", MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.Ssid)); if (check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE)) { @@ -1221,7 +1221,7 @@ static void rtw_joinbss_update_network(struct adapter *padapter, struct wlan_net DBG_871X("%s\n", __func__); - RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n" + RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:%pM\n" , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress))); /* why not use ptarget_wlan?? */ @@ -1578,7 +1578,7 @@ void rtw_stadel_event_callback(struct adapter *adapter, u8 *pbuf) else mac_id = pstadel->mac_id; - DBG_871X("%s(mac_id =%d) =" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); + DBG_871X("%s(mac_id =%d) =%pM\n", __func__, mac_id, MAC_ARG(pstadel->macaddr)); if (mac_id >= 0) { u16 media_status; @@ -1889,7 +1889,7 @@ static int rtw_check_roaming_candidate(struct mlme_priv *mlme if (rtw_is_desired_network(adapter, competitor) == false) goto exit; - DBG_871X("roam candidate:%s %s("MAC_FMT", ch%3u) rssi:%d, age:%5d\n", + DBG_871X("roam candidate:%s %s(%pM, ch%3u) rssi:%d, age:%5d\n", (competitor == mlme->cur_network_scanned)?"*":" ", competitor->network.Ssid.Ssid, MAC_ARG(competitor->network.MacAddress), @@ -1951,7 +1951,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) mlme->pscanned = get_next(mlme->pscanned); - DBG_871X("%s("MAC_FMT", ch%u) rssi:%d\n" + DBG_871X("%s(%pM, ch%u) rssi:%d\n" , pnetwork->network.Ssid.Ssid , MAC_ARG(pnetwork->network.MacAddress) , pnetwork->network.Configuration.DSConfig @@ -1966,7 +1966,7 @@ int rtw_select_roaming_candidate(struct mlme_priv *mlme) ret = _FAIL; goto exit; } else { - DBG_871X("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__, + DBG_871X("%s: candidate: %s(%pM, ch:%u)\n", __func__, candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), candidate->network.Configuration.DSConfig); @@ -2026,7 +2026,7 @@ static int rtw_check_join_candidate(struct mlme_priv *mlme if (updated) { DBG_871X("[by_bssid:%u][assoc_ssid:%s]" "[to_roam:%u] " - "new candidate: %s("MAC_FMT", ch%u) rssi:%d\n", + "new candidate: %s(%pM, ch%u) rssi:%d\n", mlme->assoc_by_bssid, mlme->assoc_ssid.Ssid, rtw_to_roam(adapter), @@ -2081,7 +2081,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) pmlmepriv->pscanned = get_next(pmlmepriv->pscanned); - DBG_871X("%s("MAC_FMT", ch%u) rssi:%d\n" + DBG_871X("%s(%pM, ch%u) rssi:%d\n" , pnetwork->network.Ssid.Ssid , MAC_ARG(pnetwork->network.MacAddress) , pnetwork->network.Configuration.DSConfig @@ -2099,7 +2099,7 @@ int rtw_select_and_join_from_scanned_queue(struct mlme_priv *pmlmepriv) ret = _FAIL; goto exit; } else { - DBG_871X("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__, + DBG_871X("%s: candidate: %s(%pM, ch:%u)\n", __func__, candidate->network.Ssid.Ssid, MAC_ARG(candidate->network.MacAddress), candidate->network.Configuration.DSConfig); goto candidate_exist; @@ -2941,7 +2941,7 @@ void _rtw_roaming(struct adapter *padapter, struct wlan_network *tgt_network) int do_join_r; if (0 < rtw_to_roam(padapter)) { - DBG_871X("roaming from %s("MAC_FMT"), length:%d\n", + DBG_871X("roaming from %s(%pM), length:%d\n", cur_network->network.Ssid.Ssid, MAC_ARG(cur_network->network.MacAddress), cur_network->network.Ssid.SsidLength); memcpy(&pmlmepriv->assoc_ssid, &cur_network->network.Ssid, sizeof(struct ndis_802_11_ssid)); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 206bb6dfac97..f81ab2541554 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -638,19 +638,19 @@ unsigned int OnProbeReq(struct adapter *padapter, union recv_frame *precv_frame) goto _non_rc_device; if (memcmp(p+6, get_sa(pframe), ETH_ALEN)) { - DBG_871X("%s, do rc pairing ("MAC_FMT"), but mac addr mismatch!("MAC_FMT")\n", __func__, + DBG_871X("%s, do rc pairing (%pM), but mac addr mismatch!(%pM)\n", __func__, MAC_ARG(get_sa(pframe)), MAC_ARG(p+6)); goto _non_rc_device; } - DBG_871X("%s, got the pairing device("MAC_FMT")\n", __func__, MAC_ARG(get_sa(pframe))); + DBG_871X("%s, got the pairing device(%pM)\n", __func__, MAC_ARG(get_sa(pframe))); /* new a station */ psta = rtw_get_stainfo(pstapriv, get_sa(pframe)); if (psta == NULL) { /* allocate a new one */ - DBG_871X("going to alloc stainfo for rc ="MAC_FMT"\n", MAC_ARG(get_sa(pframe))); + DBG_871X("going to alloc stainfo for rc =%pM\n", MAC_ARG(get_sa(pframe))); psta = rtw_alloc_stainfo(pstapriv, get_sa(pframe)); if (!psta) { /* TODO: */ @@ -787,7 +787,7 @@ unsigned int OnBeacon(struct adapter *padapter, union recv_frame *precv_frame) if (p && ielen > 0) { if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) { /* Invalid value 0x2D is detected in Extended Supported Rates (ESR) IE. Try to fix the IE length to avoid failed Beacon parsing. */ - DBG_871X("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:"MAC_FMT". Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); + DBG_871X("[WIFIDBG] Error in ESR IE is detected in Beacon of BSSID:%pM. Fix the length of ESR IE to avoid failed Beacon parsing.\n", MAC_ARG(GetAddr3Ptr(pframe))); *(p + 1) = ielen - 1; } } @@ -954,7 +954,7 @@ unsigned int OnAuth(struct adapter *padapter, union recv_frame *precv_frame) if (pstat == NULL) { /* allocate a new one */ - DBG_871X("going to alloc stainfo for sa ="MAC_FMT"\n", MAC_ARG(sa)); + DBG_871X("going to alloc stainfo for sa =%pM\n", MAC_ARG(sa)); pstat = rtw_alloc_stainfo(pstapriv, sa); if (pstat == NULL) { DBG_871X(" Exceed the upper limit of supported clients...\n"); @@ -1243,7 +1243,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) /* now parse all ieee802_11 ie to point to elems */ if (rtw_ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed || !elems.ssid) { - DBG_871X("STA " MAC_FMT " sent invalid association request\n", + DBG_871X("STA %pM sent invalid association request\n", MAC_ARG(pstat->hwaddr)); status = _STATS_FAILURE_; goto OnAssocReqFail; @@ -1407,7 +1407,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) int copy_len; if (psecuritypriv->wpa_psk == 0) { - DBG_871X("STA " MAC_FMT ": WPA/RSN IE in association " + DBG_871X("STA %pM: WPA/RSN IE in association " "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr)); status = WLAN_STATUS_INVALID_IE; @@ -1515,8 +1515,7 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) if ((pstat->flags & WLAN_STA_HT) && ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) || (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP))) { - DBG_871X("HT: " MAC_FMT " tried to " - "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); + DBG_871X("HT: %pM tried to use TKIP with HT association\n", MAC_ARG(pstat->hwaddr)); /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */ /* goto OnAssocReqFail; */ @@ -2789,7 +2788,7 @@ void issue_probersp(struct adapter *padapter, unsigned char *da, u8 is_valid_p2p /* EID[1] + EID_LEN[1] + RC_OUI[4] + MAC[6] + PairingID[2] + ChannelNum[2] */ u16 cu_ch = (u16)cur_network->Configuration.DSConfig; - DBG_871X("%s, reply rc(pid = 0x%x) device "MAC_FMT" in ch =%d\n", __func__, + DBG_871X("%s, reply rc(pid = 0x%x) device %pM in ch =%d\n", __func__, psta->pid, MAC_ARG(psta->hwaddr), cu_ch); /* append vendor specific ie */ @@ -2946,7 +2945,7 @@ int issue_probereq_ex(struct adapter *padapter, struct ndis_802_11_ssid *pssid, if (try_cnt && wait_ms) { if (da) - DBG_871X(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); else @@ -3508,7 +3507,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow else rtw_hal_macid_wakeup(padapter, psta->mac_id); } else { - DBG_871X(FUNC_ADPT_FMT ": Can't find sta info for " MAC_FMT ", skip macid %s!!\n", + DBG_871X(FUNC_ADPT_FMT ": Can't find sta info for %pM, skip macid %s!!\n", FUNC_ADPT_ARG(padapter), MAC_ARG(da), power_mode?"sleep":"wakeup"); rtw_warn_on(1); } @@ -3535,7 +3534,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow if (try_cnt && wait_ms) { if (da) - DBG_871X(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); else @@ -3683,7 +3682,7 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int if (try_cnt && wait_ms) { if (da) - DBG_871X(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); else @@ -3709,7 +3708,7 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, int ret = _FAIL; __le16 le_tmp; - /* DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */ + /* DBG_871X("%s to %pM\n", __func__, MAC_ARG(da)); */ pmgntframe = alloc_mgtxmitframe(pxmitpriv); if (pmgntframe == NULL) { @@ -3759,7 +3758,7 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, int issue_deauth(struct adapter *padapter, unsigned char *da, unsigned short reason) { - DBG_871X("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); + DBG_871X("%s to %pM\n", __func__, MAC_ARG(da)); return _issue_deauth(padapter, da, reason, false); } @@ -3791,7 +3790,7 @@ int issue_deauth_ex(struct adapter *padapter, u8 *da, unsigned short reason, int if (try_cnt && wait_ms) { if (da) - DBG_871X(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d in %u ms\n", + DBG_871X(FUNC_ADPT_FMT" to %pM, ch:%u%s, %d/%d in %u ms\n", FUNC_ADPT_ARG(padapter), MAC_ARG(da), rtw_get_oper_ch(padapter), ret == _SUCCESS?", acked":"", i, try_cnt, (i + 1) * wait_ms); else @@ -4569,7 +4568,7 @@ u8 collect_bss_info(struct adapter *padapter, union recv_frame *precv_frame, str #if defined(DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) & 1 if (strcmp(bssid->Ssid.Ssid, DBG_RX_SIGNAL_DISPLAY_SSID_MONITORED) == 0) { - DBG_871X("Receiving %s("MAC_FMT", DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" + DBG_871X("Receiving %s(%pM, DSConfig:%u) from ch%u with ss:%3u, sq:%3u, RawRSSI:%3ld\n" , bssid->Ssid.Ssid, MAC_ARG(bssid->MacAddress), bssid->Configuration.DSConfig , rtw_get_oper_ch(padapter) , bssid->PhyInfo.SignalStrength, bssid->PhyInfo.SignalQuality, bssid->Rssi @@ -5591,7 +5590,7 @@ void _linked_info_dump(struct adapter *padapter) if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); - DBG_871X("AP[" MAC_FMT "] - UndecoratedSmoothedPWDB:%d\n", + DBG_871X("AP[%pM] - UndecoratedSmoothedPWDB:%d\n", MAC_ARG(padapter->mlmepriv.cur_network.network.MacAddress), UndecoratedSmoothedPWDB); } else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_) { struct list_head *phead, *plist; @@ -5606,7 +5605,7 @@ void _linked_info_dump(struct adapter *padapter) psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); plist = get_next(plist); - DBG_871X("STA[" MAC_FMT "]:UndecoratedSmoothedPWDB:%d\n", + DBG_871X("STA[%pM]:UndecoratedSmoothedPWDB:%d\n", MAC_ARG(psta->hwaddr), psta->rssi_stat.UndecoratedSmoothedPWDB); } spin_unlock_bh(&pstapriv->asoc_list_lock); @@ -6456,7 +6455,7 @@ u8 setkey_hdl(struct adapter *padapter, u8 *pbuf) ctrl = BIT(15) | BIT6 | ((pparm->algorithm) << 2) | pparm->keyid; write_cam(padapter, cam_id, ctrl, addr, pparm->key); - DBG_871X_LEVEL(_drv_always_, "set group key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n" + DBG_871X_LEVEL(_drv_always_, "set group key camid:%d, addr:%pM, kid:%d, type:%s\n" , cam_id, MAC_ARG(addr), pparm->keyid, security_type_str(pparm->algorithm)); } @@ -6485,7 +6484,7 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) psta = rtw_get_stainfo(pstapriv, pparm->addr); if (!psta) { - DBG_871X_LEVEL(_drv_always_, "%s sta:"MAC_FMT" not found\n", __func__, MAC_ARG(pparm->addr)); + DBG_871X_LEVEL(_drv_always_, "%s sta:%pM not found\n", __func__, MAC_ARG(pparm->addr)); ret = H2C_REJECTED; goto exit; } @@ -6498,12 +6497,12 @@ u8 set_stakey_hdl(struct adapter *padapter, u8 *pbuf) write_to_cam: if (pparm->algorithm == _NO_PRIVACY_) { while ((cam_id = rtw_camid_search(padapter, pparm->addr, -1)) >= 0) { - DBG_871X_LEVEL(_drv_always_, "clear key for addr:"MAC_FMT", camid:%d\n", MAC_ARG(pparm->addr), cam_id); + DBG_871X_LEVEL(_drv_always_, "clear key for addr:%pM, camid:%d\n", MAC_ARG(pparm->addr), cam_id); clear_cam_entry(padapter, cam_id); rtw_camid_free(padapter, cam_id); } } else { - DBG_871X_LEVEL(_drv_always_, "set pairwise key camid:%d, addr:"MAC_FMT", kid:%d, type:%s\n", + DBG_871X_LEVEL(_drv_always_, "set pairwise key camid:%d, addr:%pM, kid:%d, type:%s\n", cam_id, MAC_ARG(pparm->addr), pparm->keyid, security_type_str(pparm->algorithm)); ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid; write_cam(padapter, cam_id, ctrl, pparm->addr, pparm->key); diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 560c188f0309..26e72decb07e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -893,7 +893,7 @@ sint ap2sta_data_frame( if (!memcmp(myhwaddr, pattrib->src, ETH_ALEN)) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" SA ==myself\n")); #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s SA ="MAC_FMT", myhwaddr ="MAC_FMT"\n", + DBG_871X("DBG_RX_DROP_FRAME %s SA =%pM, myhwaddr =%pM\n", __func__, MAC_ARG(pattrib->src), MAC_ARG(myhwaddr)); #endif ret = _FAIL; @@ -903,9 +903,9 @@ sint ap2sta_data_frame( /* da should be for me */ if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) { RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare DA fail; DA ="MAC_FMT"\n", MAC_ARG(pattrib->dst))); + (" ap2sta_data_frame: compare DA fail; DA =%pM\n", MAC_ARG(pattrib->dst))); #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s DA ="MAC_FMT"\n", __func__, MAC_ARG(pattrib->dst)); + DBG_871X("DBG_RX_DROP_FRAME %s DA =%pM\n", __func__, MAC_ARG(pattrib->dst)); #endif ret = _FAIL; goto exit; @@ -917,16 +917,16 @@ sint ap2sta_data_frame( !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) { RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, - (" ap2sta_data_frame: compare BSSID fail ; BSSID ="MAC_FMT"\n", MAC_ARG(pattrib->bssid))); - RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid ="MAC_FMT"\n", MAC_ARG(mybssid))); + (" ap2sta_data_frame: compare BSSID fail ; BSSID =%pM\n", MAC_ARG(pattrib->bssid))); + RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("mybssid =%pM\n", MAC_ARG(mybssid))); #ifdef DBG_RX_DROP_FRAME - DBG_871X("DBG_RX_DROP_FRAME %s BSSID ="MAC_FMT", mybssid ="MAC_FMT"\n", + DBG_871X("DBG_RX_DROP_FRAME %s BSSID =%pM, mybssid =%pM\n", __func__, MAC_ARG(pattrib->bssid), MAC_ARG(mybssid)); DBG_871X("this adapter = %d, buddy adapter = %d\n", adapter->adapter_type, adapter->pbuddystruct adapter->adapter_type); #endif if (!bmcast) { - DBG_871X("issue_deauth to the nonassociated ap =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); + DBG_871X("issue_deauth to the nonassociated ap =%pM for the reason(7)\n", MAC_ARG(pattrib->bssid)); issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); } @@ -998,7 +998,7 @@ sint ap2sta_data_frame( if (jiffies_to_msecs(jiffies - send_issue_deauth_time) > 10000 || send_issue_deauth_time == 0) { send_issue_deauth_time = jiffies; - DBG_871X("issue_deauth to the ap =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->bssid)); + DBG_871X("issue_deauth to the ap =%pM for the reason(7)\n", MAC_ARG(pattrib->bssid)); issue_deauth(adapter, pattrib->bssid, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); } @@ -1041,7 +1041,7 @@ sint sta2ap_data_frame( *psta = rtw_get_stainfo(pstapriv, pattrib->src); if (!*psta) { RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under AP_MODE; drop pkt\n")); - DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); + DBG_871X("issue_deauth to sta =%pM for the reason(7)\n", MAC_ARG(pattrib->src)); issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); @@ -1067,7 +1067,7 @@ sint sta2ap_data_frame( ret = RTW_RX_HANDLED; goto exit; } - DBG_871X("issue_deauth to sta =" MAC_FMT " for the reason(7)\n", MAC_ARG(pattrib->src)); + DBG_871X("issue_deauth to sta =%pM for the reason(7)\n", MAC_ARG(pattrib->src)); issue_deauth(adapter, pattrib->src, WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA); ret = RTW_RX_HANDLED; goto exit; @@ -1653,7 +1653,7 @@ sint wlanhdr_to_ethhdr(union recv_frame *precvframe) rx_pid = *(u16 *)(ptr+rmv_len+2); - DBG_871X("wlan rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n", + DBG_871X("wlan rx(pid = 0x%x): sta(%pM) pid = 0x%x\n", rx_pid, MAC_ARG(psta->hwaddr), psta->pid); if (rx_pid == psta->pid) { diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index e3e8140eec9e..e1c278501779 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -628,7 +628,7 @@ static s16 _rtw_camid_search(struct adapter *adapter, u8 *addr, s16 kid) } if (addr) - DBG_871X(FUNC_ADPT_FMT" addr:"MAC_FMT" kid:%d, return cam_id:%d\n" + DBG_871X(FUNC_ADPT_FMT" addr:%pM kid:%d, return cam_id:%d\n" , FUNC_ADPT_ARG(adapter), MAC_ARG(addr), kid, cam_id); else DBG_871X(FUNC_ADPT_FMT" addr:%p kid:%d, return cam_id:%d\n" @@ -702,7 +702,7 @@ s16 rtw_camid_alloc(struct adapter *adapter, struct sta_info *sta, u8 kid) if (i == TOTAL_CAM_ENTRY) { if (sta) - DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pairwise key with "MAC_FMT" id:%u no room\n" + DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" pairwise key with %pM id:%u no room\n" , FUNC_ADPT_ARG(adapter), MAC_ARG(sta->hwaddr), kid); else DBG_871X_LEVEL(_drv_always_, FUNC_ADPT_FMT" group key id:%u no room\n" @@ -1251,7 +1251,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } if (memcmp(cur_network->network.MacAddress, pbssid, 6)) { - DBG_871X("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT, + DBG_871X("Oops: rtw_check_network_encrypt linked but recv other bssid bcn %pM %pM\n", MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress)); return true; } diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 10a34bce1f67..aaafa38c34c4 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -736,9 +736,9 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib psta = rtw_get_stainfo(pstapriv, pattrib->ra); if (!psta) { /* if we cannot get psta => drop the pkt */ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_ucast_sta); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT"\n", MAC_ARG(pattrib->ra))); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", MAC_ARG(pattrib->ra))); #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); + DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:%pM\n", __func__, MAC_ARG(pattrib->ra)); #endif res = _FAIL; goto exit; @@ -752,9 +752,9 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib if (!psta) { /* if we cannot get psta => drop the pkt */ DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_sta); - RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT "\n", MAC_ARG(pattrib->ra))); + RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_, ("\nupdate_attrib => get sta_info fail, ra:%pM\n", MAC_ARG(pattrib->ra))); #ifdef DBG_TX_DROP_FRAME - DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:" MAC_FMT"\n", __func__, MAC_ARG(pattrib->ra)); + DBG_871X("DBG_TX_DROP_FRAME %s get sta_info fail, ra:%pM\n", __func__, MAC_ARG(pattrib->ra)); #endif res = _FAIL; goto exit; @@ -762,7 +762,7 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib if (!(psta->state & _FW_LINKED)) { DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_err_link); - DBG_871X("%s, psta("MAC_FMT")->state(0x%x) != _FW_LINKED\n", __func__, MAC_ARG(psta->hwaddr), psta->state); + DBG_871X("%s, psta(%pM)->state(0x%x) != _FW_LINKED\n", __func__, MAC_ARG(psta->hwaddr), psta->state); return _FAIL; } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c index fd2b74003faf..a6d870d663a4 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c @@ -415,7 +415,7 @@ static void ConstructARPResponse( { SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); - DBG_871X("%s Target Mac Addr:" MAC_FMT "\n", __func__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); + DBG_871X("%s Target Mac Addr:%pM\n", __func__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); DBG_871X("%s Target IP Addr" IP_FMT "\n", __func__, IP_ARG(pIPAddress)); } @@ -737,7 +737,7 @@ static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength memcpy(pwlanhdr->addr2, mac, ETH_ALEN); memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); - DBG_871X("%s FW Mac Addr:" MAC_FMT "\n", __func__, MAC_ARG(mac)); + DBG_871X("%s FW Mac Addr:%pM\n", __func__, MAC_ARG(mac)); DBG_871X("%s FW IP Addr" IP_FMT "\n", __func__, IP_ARG(StaAddr)); SetSeqNum(pwlanhdr, 0); diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index b7c4b1cf204e..902c710c1155 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -844,7 +844,6 @@ enum ieee80211_state { #define DEFAULT_MAX_SCAN_AGE (15 * HZ) #define DEFAULT_FTS 2346 -#define MAC_FMT "%pM" #define MAC_ARG(x) (x) #define IP_FMT "%pI4" #define IP_ARG(x) (x) diff --git a/drivers/staging/rtl8723bs/include/osdep_service.h b/drivers/staging/rtl8723bs/include/osdep_service.h index a94b72397ce7..dcc3cdce6d4b 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service.h +++ b/drivers/staging/rtl8723bs/include/osdep_service.h @@ -132,9 +132,6 @@ static inline int rtw_bug_check(void *parg1, void *parg2, void *parg3, void *par #define _RND(sz, r) ((((sz)+((r)-1))/(r))*(r)) -#ifndef MAC_FMT -#define MAC_FMT "%pM" -#endif #ifndef MAC_ARG #define MAC_ARG(x) (x) #endif diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 6b86f76bba77..5dfa2fa24c76 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -481,7 +481,7 @@ void rtw_cfg80211_indicate_connect(struct adapter *padapter) /* DBG_871X(FUNC_ADPT_FMT" inform success !!\n", FUNC_ADPT_ARG(padapter)); */ } } else { - DBG_871X("scanned: %s("MAC_FMT"), cur: %s("MAC_FMT")\n", + DBG_871X("scanned: %s(%pM), cur: %s(%pM)\n", scanned->network.Ssid.Ssid, MAC_ARG(scanned->network.MacAddress), pnetwork->Ssid.Ssid, MAC_ARG(pnetwork->MacAddress) ); @@ -1222,7 +1222,7 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, } #ifdef DEBUG_CFG80211 - DBG_871X(FUNC_NDEV_FMT" mac ="MAC_FMT"\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); + DBG_871X(FUNC_NDEV_FMT" mac =%pM\n", FUNC_NDEV_ARG(ndev), MAC_ARG(mac)); #endif /* for infra./P2PClient mode */ @@ -1233,7 +1233,7 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy, struct wlan_network *cur_network = &(pmlmepriv->cur_network); if (memcmp((u8 *)mac, cur_network->network.MacAddress, ETH_ALEN)) { - DBG_871X("%s, mismatch bssid ="MAC_FMT"\n", __func__, MAC_ARG(cur_network->network.MacAddress)); + DBG_871X("%s, mismatch bssid =%pM\n", __func__, MAC_ARG(cur_network->network.MacAddress)); ret = -ENOENT; goto exit; } @@ -2079,7 +2079,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, if (sme->bssid) - DBG_8192C("bssid ="MAC_FMT"\n", MAC_ARG(sme->bssid)); + DBG_8192C("bssid =%pM\n", MAC_ARG(sme->bssid)); if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) { @@ -2502,7 +2502,7 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc goto fail; } - DBG_8192C("RTW_Tx:da ="MAC_FMT" via "FUNC_NDEV_FMT"\n", + DBG_8192C("RTW_Tx:da =%pM via "FUNC_NDEV_FMT"\n", MAC_ARG(GetAddr1Ptr(buf)), FUNC_NDEV_ARG(ndev)); if (category == RTW_WLAN_CATEGORY_PUBLIC) DBG_871X("RTW_Tx:%s\n", action_public_str(action)); @@ -2838,7 +2838,7 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev } - DBG_8192C("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac)); + DBG_8192C("free sta macaddr =%pM\n", MAC_ARG(mac)); if (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff && mac[3] == 0xff && @@ -3102,7 +3102,7 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, goto exit; } - DBG_8192C("RTW_Tx:tx_ch =%d, da ="MAC_FMT"\n", tx_ch, MAC_ARG(GetAddr1Ptr(buf))); + DBG_8192C("RTW_Tx:tx_ch =%d, da =%pM\n", tx_ch, MAC_ARG(GetAddr1Ptr(buf))); if (category == RTW_WLAN_CATEGORY_PUBLIC) DBG_871X("RTW_Tx:%s\n", action_public_str(action)); else diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 68c1a8d0b7ba..3f3eab3d879a 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -2489,7 +2489,7 @@ static int rtw_get_ap_info(struct net_device *dev, if (!memcmp(bssid, pnetwork->network.MacAddress, ETH_ALEN)) { /* BSSID match, then check if supporting wpa/wpa2 */ - DBG_871X("BSSID:" MAC_FMT "\n", MAC_ARG(bssid)); + DBG_871X("BSSID:%pM\n", MAC_ARG(bssid)); pbuf = rtw_get_wpa_ie(&pnetwork->network.IEs[12], &wpa_ielen, pnetwork->network.IELength-12); if (pbuf && (wpa_ielen > 0)) { @@ -2799,7 +2799,7 @@ static int rtw_dbg_port(struct net_device *dev, struct recv_reorder_ctrl *preorder_ctrl; DBG_871X("SSID =%s\n", cur_network->network.Ssid.Ssid); - DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + DBG_871X("sta's macaddr:%pM\n", MAC_ARG(psta->hwaddr)); DBG_871X("cur_channel =%d, cur_bwmode =%d, cur_ch_offset =%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); @@ -2815,7 +2815,7 @@ static int rtw_dbg_port(struct net_device *dev, } } else { - DBG_871X("can't get sta's macaddr, cur_network's macaddr:" MAC_FMT "\n", MAC_ARG(cur_network->network.MacAddress)); + DBG_871X("can't get sta's macaddr, cur_network's macaddr:%pM\n", MAC_ARG(cur_network->network.MacAddress)); } break; case 0x06: @@ -2857,7 +2857,7 @@ static int rtw_dbg_port(struct net_device *dev, plist = get_next(plist); if (extra_arg == psta->aid) { - DBG_871X("sta's macaddr:" MAC_FMT "\n", MAC_ARG(psta->hwaddr)); + DBG_871X("sta's macaddr:%pM\n", MAC_ARG(psta->hwaddr)); DBG_871X("rtsen =%d, cts2slef =%d\n", psta->rtsen, psta->cts2self); DBG_871X("state = 0x%x, aid =%d, macid =%d, raid =%d\n", psta->state, psta->aid, psta->mac_id, psta->raid); DBG_871X("qos_en =%d, ht_en =%d, init_rate =%d\n", psta->qos_option, psta->htpriv.ht_option, psta->init_rate); @@ -3745,7 +3745,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_add_sta(aid =%d) =" MAC_FMT "\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); + DBG_871X("rtw_add_sta(aid =%d) =%pM\n", param->u.add_sta.aid, MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3820,7 +3820,7 @@ static int rtw_del_sta(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_del_sta =" MAC_FMT "\n", MAC_ARG(param->sta_addr)); + DBG_871X("rtw_del_sta =%pM\n", MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3871,7 +3871,7 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par struct ieee_param_ex *param_ex = (struct ieee_param_ex *)param; struct sta_data *psta_data = (struct sta_data *)param_ex->data; - DBG_871X("rtw_ioctl_get_sta_info, sta_addr: " MAC_FMT "\n", MAC_ARG(param_ex->sta_addr)); + DBG_871X("rtw_ioctl_get_sta_info, sta_addr: %pM\n", MAC_ARG(param_ex->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; @@ -3932,7 +3932,7 @@ static int rtw_get_sta_wpaie(struct net_device *dev, struct ieee_param *param) struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct sta_priv *pstapriv = &padapter->stapriv; - DBG_871X("rtw_get_sta_wpaie, sta_addr: " MAC_FMT "\n", MAC_ARG(param->sta_addr)); + DBG_871X("rtw_get_sta_wpaie, sta_addr: %pM\n", MAC_ARG(param->sta_addr)); if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) return -EINVAL; diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index 2aaccf453907..ed8212b7deb4 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -864,7 +864,7 @@ static int _rtw_drv_register_netdev(struct adapter *padapter, char *name) goto error_register_netdev; } - DBG_871X("%s, MAC Address (if%d) = " MAC_FMT "\n", __func__, (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr)); + DBG_871X("%s, MAC Address (if%d) = %pM\n", __func__, (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr)); return ret; @@ -913,7 +913,7 @@ int _netdev_open(struct net_device *pnetdev) goto netdev_open_error; } - DBG_871X("MAC Address = " MAC_FMT "\n", MAC_ARG(pnetdev->dev_addr)); + DBG_871X("MAC Address = %pM\n", MAC_ARG(pnetdev->dev_addr)); status = rtw_start_drv_threads(padapter); if (status == _FAIL) { @@ -1209,7 +1209,7 @@ static int rtw_suspend_free_assoc_resource(struct adapter *padapter) if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__, + DBG_871X("%s %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, pmlmepriv->cur_network.network.Ssid.Ssid, MAC_ARG(pmlmepriv->cur_network.network.MacAddress), pmlmepriv->cur_network.network.Ssid.SsidLength, @@ -1284,7 +1284,7 @@ void rtw_suspend_wow(struct adapter *padapter) padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_WOWLAN, (u8 *)&poidparam); if (rtw_chk_roam_flags(padapter, RTW_ROAM_ON_RESUME)) { if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED)) { - DBG_871X("%s %s(" MAC_FMT "), length:%d assoc_ssid.length:%d\n", __func__, + DBG_871X("%s %s(%pM), length:%d assoc_ssid.length:%d\n", __func__, pmlmepriv->cur_network.network.Ssid.Ssid, MAC_ARG(pmlmepriv->cur_network.network.MacAddress), pmlmepriv->cur_network.network.Ssid.SsidLength, diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 4a1d5293a327..63c1998bec7f 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -220,7 +220,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec rx_pid = *(u16*)(skb->data+ETH_HLEN); - DBG_871X("eth rx(pid = 0x%x): sta("MAC_FMT") pid = 0x%x\n", + DBG_871X("eth rx(pid = 0x%x): sta(%pM) pid = 0x%x\n", rx_pid, MAC_ARG(psta->hwaddr), psta->pid); if (rx_pid == psta->pid) { -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:48 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:48 -0600 Subject: [PATCH 3/9] staging: rtl8723bs: remove IP_FMT macro In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-3-ross.schm.dev@gmail.com> Remove unnecessary macro for %pI4 and call it directly. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c | 4 ++-- drivers/staging/rtl8723bs/include/ieee80211.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c index a6d870d663a4..93c93cdaadaf 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c @@ -416,7 +416,7 @@ static void ConstructARPResponse( SET_ARP_PKT_TARGET_MAC_ADDR(pARPRspPkt, get_my_bssid(&(pmlmeinfo->network))); SET_ARP_PKT_TARGET_IP_ADDR(pARPRspPkt, pIPAddress); DBG_871X("%s Target Mac Addr:%pM\n", __func__, MAC_ARG(get_my_bssid(&(pmlmeinfo->network)))); - DBG_871X("%s Target IP Addr" IP_FMT "\n", __func__, IP_ARG(pIPAddress)); + DBG_871X("%s Target IP Addr:%pI4\n", __func__, IP_ARG(pIPAddress)); } *pLength += 28; @@ -738,7 +738,7 @@ static void ConstructProbeRsp(struct adapter *padapter, u8 *pframe, u32 *pLength memcpy(pwlanhdr->addr3, bssid, ETH_ALEN); DBG_871X("%s FW Mac Addr:%pM\n", __func__, MAC_ARG(mac)); - DBG_871X("%s FW IP Addr" IP_FMT "\n", __func__, IP_ARG(StaAddr)); + DBG_871X("%s FW IP Addr:%pI4\n", __func__, IP_ARG(StaAddr)); SetSeqNum(pwlanhdr, 0); SetFrameSubType(fctrl, WIFI_PROBERSP); diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index 902c710c1155..5cd307cb48a5 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -845,7 +845,6 @@ enum ieee80211_state { #define DEFAULT_MAX_SCAN_AGE (15 * HZ) #define DEFAULT_FTS 2346 #define MAC_ARG(x) (x) -#define IP_FMT "%pI4" #define IP_ARG(x) (x) static inline int is_multicast_mac_addr(const u8 *addr) -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:49 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:49 -0600 Subject: [PATCH 4/9] staging: rtl8723bs: remove NDEV_FMT macro In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-4-ross.schm.dev@gmail.com> Remove unnecessary macro for %s and call it directly. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/include/osdep_service_linux.h | 1 - drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/rtl8723bs/include/osdep_service_linux.h b/drivers/staging/rtl8723bs/include/osdep_service_linux.h index 498d5474010c..24386aa9ee1b 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h +++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h @@ -123,7 +123,6 @@ static inline void rtw_netif_stop_queue(struct net_device *pnetdev) #define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)), (sig), 1) -#define NDEV_FMT "%s" #define NDEV_ARG(ndev) ndev->name #define ADPT_FMT "%s" #define ADPT_ARG(adapter) adapter->pnetdev->name diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 5dfa2fa24c76..736f1a6ac118 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -2574,7 +2574,7 @@ static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, str } if (pwdev_priv->pmon_ndev) { - DBG_871X(FUNC_ADPT_FMT" monitor interface exist: "NDEV_FMT"\n", + DBG_871X(FUNC_ADPT_FMT" monitor interface exist: %s\n", FUNC_ADPT_ARG(padapter), NDEV_ARG(pwdev_priv->pmon_ndev)); ret = -EBUSY; goto out; -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:50 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:50 -0600 Subject: [PATCH 5/9] staging: rtl8723bs: remove ADPT_FMT macro In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-5-ross.schm.dev@gmail.com> Remove unnecessary macro for %s and call it directly. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_cmd.c | 2 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 4 ++-- drivers/staging/rtl8723bs/core/rtw_security.c | 4 ++-- drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 6 +++--- drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c | 12 ++++++------ drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c | 2 +- .../staging/rtl8723bs/include/osdep_service_linux.h | 1 - 7 files changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 4e11cd97cc01..d0772b4fe15d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -503,7 +503,7 @@ int rtw_cmd_thread(void *context) cmd_process_time = jiffies_to_msecs(jiffies - cmd_start_time); if (cmd_process_time > 1000) { - DBG_871X(ADPT_FMT "cmd= %d process_time= %lu > 1 sec\n", + DBG_871X("%s cmd= %d process_time= %lu > 1 sec\n", ADPT_ARG(pcmd->padapter), pcmd->cmdcode, cmd_process_time); } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index f81ab2541554..a0bb25031f1a 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -5108,7 +5108,7 @@ void report_surveydone_event(struct adapter *padapter) psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; - DBG_871X("survey done event(%x) band:%d for "ADPT_FMT"\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter)); + DBG_871X("survey done event(%x) band:%d for %s\n", psurveydone_evt->bss_cnt, padapter->setband, ADPT_ARG(padapter)); rtw_enqueue_cmd(pcmdpriv, pcmd_obj); @@ -5585,7 +5585,7 @@ void _linked_info_dump(struct adapter *padapter) if (padapter->bLinkInfoDump) { - DBG_871X("\n ============["ADPT_FMT"] linked status check ===================\n", ADPT_ARG(padapter)); + DBG_871X("\n ============[%s] linked status check ===================\n", ADPT_ARG(padapter)); if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) { rtw_hal_get_def_var(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB); diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 82e26acb772c..81c15895f646 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -2372,12 +2372,12 @@ u8 rtw_handle_tkip_countermeasure(struct adapter *adapter, const char *caller) if (securitypriv->btkip_countermeasure) { unsigned long passing_ms = jiffies_to_msecs(jiffies - securitypriv->btkip_countermeasure_time); if (passing_ms > 60*1000) { - DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%lus > 60s\n", + DBG_871X_LEVEL(_drv_always_, "%s(%s) countermeasure time:%lus > 60s\n", caller, ADPT_ARG(adapter), passing_ms/1000); securitypriv->btkip_countermeasure = false; securitypriv->btkip_countermeasure_time = 0; } else { - DBG_871X_LEVEL(_drv_always_, "%s("ADPT_FMT") countermeasure time:%lus < 60s\n", + DBG_871X_LEVEL(_drv_always_, "%s(%s) countermeasure time:%lus < 60s\n", caller, ADPT_ARG(adapter), passing_ms/1000); status = _FAIL; } diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index e1c278501779..eda91b78a543 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -304,7 +304,7 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) for (i = 0; i < dvobj->iface_nums; i++) { struct adapter *iface = dvobj->padapters[i]; - cnt += scnprintf(msg+cnt, len-cnt, " ["ADPT_FMT":", ADPT_ARG(iface)); + cnt += scnprintf(msg+cnt, len-cnt, " [%s:", ADPT_ARG(iface)); if (iface->mlmeextpriv.cur_channel == ch) cnt += scnprintf(msg+cnt, len-cnt, "C"); else @@ -1431,11 +1431,11 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) pmlmepriv->timeBcnInfoChkStart = jiffies; pmlmepriv->NumOfBcnInfoChkFail++; - DBG_871X("%s by "ADPT_FMT" - NumOfChkFail = %d (SeqNum of this Beacon frame = %d).\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, GetSequence(pframe)); + DBG_871X("%s by %s - NumOfChkFail = %d (SeqNum of this Beacon frame = %d).\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, GetSequence(pframe)); if ((pmlmepriv->timeBcnInfoChkStart != 0) && (jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart) <= DISCONNECT_BY_CHK_BCN_FAIL_OBSERV_PERIOD_IN_MS) && (pmlmepriv->NumOfBcnInfoChkFail >= DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD)) { - DBG_871X("%s by "ADPT_FMT" - NumOfChkFail = %d >= threshold : %d (in %d ms), return FAIL.\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, + DBG_871X("%s by %s - NumOfChkFail = %d >= threshold : %d (in %d ms), return FAIL.\n", __func__, ADPT_ARG(Adapter), pmlmepriv->NumOfBcnInfoChkFail, DISCONNECT_BY_CHK_BCN_FAIL_THRESHOLD, jiffies_to_msecs(jiffies - pmlmepriv->timeBcnInfoChkStart)); pmlmepriv->timeBcnInfoChkStart = 0; pmlmepriv->NumOfBcnInfoChkFail = 0; diff --git a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c index 93c93cdaadaf..56fea55513ba 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723b_cmd.c @@ -1993,12 +1993,12 @@ void rtl8723b_download_rsvd_page(struct adapter *padapter, u8 mstatus) if (padapter->bSurpriseRemoved || padapter->bDriverStopped) { } else if (!bcn_valid) - DBG_871X(ADPT_FMT": 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n", + DBG_871X("%s: 1 DL RSVD page failed! DLBcnCount:%u, poll:%u\n", ADPT_ARG(padapter), DLBcnCount, poll); else { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); pwrctl->fw_psmode_iface_id = padapter->iface_id; - DBG_871X(ADPT_FMT": 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n", + DBG_871X("%s: 1 DL RSVD page success! DLBcnCount:%u, poll:%u\n", ADPT_ARG(padapter), DLBcnCount, poll); } @@ -2290,14 +2290,14 @@ void rtl8723b_download_BTCoex_AP_mode_rsvd_page(struct adapter *padapter) if (bcn_valid) { struct pwrctrl_priv *pwrctl = adapter_to_pwrctl(padapter); pwrctl->fw_psmode_iface_id = padapter->iface_id; - DBG_8192C(ADPT_FMT": DL RSVD page success! DLBcnCount:%d, poll:%d\n", + DBG_8192C("%s: DL RSVD page success! DLBcnCount:%d, poll:%d\n", ADPT_ARG(padapter), DLBcnCount, poll); } else { - DBG_8192C(ADPT_FMT": DL RSVD page fail! DLBcnCount:%d, poll:%d\n", + DBG_8192C("%s: DL RSVD page fail! DLBcnCount:%d, poll:%d\n", ADPT_ARG(padapter), DLBcnCount, poll); - DBG_8192C(ADPT_FMT": DL RSVD page fail! bSurpriseRemoved =%d\n", + DBG_8192C("%s: DL RSVD page fail! bSurpriseRemoved =%d\n", ADPT_ARG(padapter), padapter->bSurpriseRemoved); - DBG_8192C(ADPT_FMT": DL RSVD page fail! bDriverStopped =%d\n", + DBG_8192C("%s: DL RSVD page fail! bDriverStopped =%d\n", ADPT_ARG(padapter), padapter->bDriverStopped); } diff --git a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c index 44799c4a9f35..6f9d082be7f3 100644 --- a/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c +++ b/drivers/staging/rtl8723bs/hal/rtl8723bs_xmit.c @@ -482,7 +482,7 @@ int rtl8723bs_xmit_thread(void *context) padapter = context; pxmitpriv = &padapter->xmitpriv; - rtw_sprintf(thread_name, 20, "RTWHALXT-" ADPT_FMT, ADPT_ARG(padapter)); + rtw_sprintf(thread_name, 20, "RTWHALXT-%s", ADPT_ARG(padapter)); thread_enter(thread_name); DBG_871X("start "FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter)); diff --git a/drivers/staging/rtl8723bs/include/osdep_service_linux.h b/drivers/staging/rtl8723bs/include/osdep_service_linux.h index 24386aa9ee1b..8608bc251eea 100644 --- a/drivers/staging/rtl8723bs/include/osdep_service_linux.h +++ b/drivers/staging/rtl8723bs/include/osdep_service_linux.h @@ -124,7 +124,6 @@ static inline void rtw_netif_stop_queue(struct net_device *pnetdev) #define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)), (sig), 1) #define NDEV_ARG(ndev) ndev->name -#define ADPT_FMT "%s" #define ADPT_ARG(adapter) adapter->pnetdev->name #define FUNC_NDEV_FMT "%s(%s)" #define FUNC_NDEV_ARG(ndev) __func__, ndev->name -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:51 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:51 -0600 Subject: [PATCH 6/9] staging: rtl8723bs: replace rtw_ieee80211_ht_cap In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-6-ross.schm.dev@gmail.com> Replace the unique rtw_ieee80211_ht_cap struct with the provided standard ieee80211_ht_cap. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_ap.c | 6 +++--- .../staging/rtl8723bs/core/rtw_ioctl_set.c | 2 +- drivers/staging/rtl8723bs/core/rtw_mlme.c | 20 +++++++++---------- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 8 ++++---- .../staging/rtl8723bs/core/rtw_wlan_util.c | 4 ++-- drivers/staging/rtl8723bs/hal/hal_com.c | 2 +- drivers/staging/rtl8723bs/include/ieee80211.h | 4 ++-- drivers/staging/rtl8723bs/include/rtw_ht.h | 2 +- drivers/staging/rtl8723bs/include/wifi.h | 16 --------------- .../staging/rtl8723bs/os_dep/ioctl_linux.c | 10 +++++----- 10 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_ap.c b/drivers/staging/rtl8723bs/core/rtw_ap.c index d9a55bee83a3..a2b39ae56d89 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ap.c +++ b/drivers/staging/rtl8723bs/core/rtw_ap.c @@ -1179,7 +1179,7 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) if (p && ie_len > 0) { u8 rf_type = 0; u8 max_rx_ampdu_factor = 0; - struct rtw_ieee80211_ht_cap *pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); + struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p + 2); pHT_caps_ie = p; @@ -1225,8 +1225,8 @@ int rtw_check_beacon_data(struct adapter *padapter, u8 *pbuf, int len) rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); if (rf_type == RF_1T1R) { - pht_cap->supp_mcs_set[0] = 0xff; - pht_cap->supp_mcs_set[1] = 0x0; + pht_cap->mcs.rx_mask[0] = 0xff; + pht_cap->mcs.rx_mask[1] = 0x0; } memcpy(&pmlmepriv->htpriv.ht_cap, p + 2, ie_len); diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c index d44b33e7a0a9..e0bab0a71f00 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c @@ -661,7 +661,7 @@ u16 rtw_get_cur_max_rate(struct adapter *adapter) rf_type, ((psta->bw_mode == CHANNEL_WIDTH_40)?1:0), short_GI, - psta->htpriv.ht_cap.supp_mcs_set + psta->htpriv.ht_cap.mcs.rx_mask ); } else { while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) { diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme.c b/drivers/staging/rtl8723bs/core/rtw_mlme.c index b5226a517b91..351178ab78c5 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme.c @@ -2582,7 +2582,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ u32 ielen, out_len; enum HT_CAP_AMPDU_FACTOR max_rx_ampdu_factor; unsigned char *p, *pframe; - struct rtw_ieee80211_ht_cap ht_capie; + struct ieee80211_ht_cap ht_capie; u8 cbw40_enable = 0, stbc_rx_enable = 0, rf_type = 0, operation_bw = 0; struct registry_priv *pregistrypriv = &padapter->registrypriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -2593,7 +2593,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ out_len = *pout_len; - memset(&ht_capie, 0, sizeof(struct rtw_ieee80211_ht_cap)); + memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap)); ht_capie.cap_info = cpu_to_le16(IEEE80211_HT_CAP_DSSSCCK40); @@ -2660,7 +2660,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ } /* fill default supported_mcs_set */ - memcpy(ht_capie.supp_mcs_set, pmlmeext->default_supported_mcs_set, 16); + memcpy(ht_capie.mcs.rx_mask, pmlmeext->default_supported_mcs_set, 16); /* update default supported_mcs_set */ rtw_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); @@ -2670,7 +2670,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ if (stbc_rx_enable) ht_capie.cap_info |= cpu_to_le16(IEEE80211_HT_CAP_RX_STBC_1R);/* RX STBC One spatial stream */ - set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_1R); + set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_1R); break; case RF_2T2R: @@ -2681,11 +2681,11 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ #ifdef CONFIG_DISABLE_MCS13TO15 if (((cbw40_enable == 1) && (operation_bw == CHANNEL_WIDTH_40)) && (pregistrypriv->wifi_spec != 1)) - set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R_13TO15_OFF); + set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R_13TO15_OFF); else - set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R); + set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R); #else /* CONFIG_DISABLE_MCS13TO15 */ - set_mcs_rate_by_mask(ht_capie.supp_mcs_set, MCS_RATE_2R); + set_mcs_rate_by_mask(ht_capie.mcs.rx_mask, MCS_RATE_2R); #endif /* CONFIG_DISABLE_MCS13TO15 */ break; } @@ -2712,7 +2712,7 @@ unsigned int rtw_restructure_ht_ie(struct adapter *padapter, u8 *in_ie, u8 *out_ ht_capie.ampdu_params_info |= (IEEE80211_HT_CAP_AMPDU_DENSITY&0x00); pframe = rtw_set_ie(out_ie+out_len, _HT_CAPABILITY_IE_, - sizeof(struct rtw_ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len); + sizeof(struct ieee80211_ht_cap), (unsigned char *)&ht_capie, pout_len); phtpriv->ht_option = true; @@ -2734,7 +2734,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe u8 *p, max_ampdu_sz; int len; /* struct sta_info *bmc_sta, *psta; */ - struct rtw_ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_cap *pht_capie; struct ieee80211_ht_addt_info *pht_addtinfo; /* struct recv_reorder_ctrl *preorder_ctrl; */ struct mlme_priv *pmlmepriv = &padapter->mlmepriv; @@ -2763,7 +2763,7 @@ void rtw_update_ht_cap(struct adapter *padapter, u8 *pie, uint ie_len, u8 channe len = 0; p = rtw_get_ie(pie+sizeof(struct ndis_802_11_fix_ie), _HT_CAPABILITY_IE_, &len, ie_len-sizeof(struct ndis_802_11_fix_ie)); if (p && len > 0) { - pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); + pht_capie = (struct ieee80211_ht_cap *)(p+2); max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_CAP_AMPDU_FACTOR); max_ampdu_sz = 1 << (max_ampdu_sz+3); /* max_ampdu_sz (kbytes); */ diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index a0bb25031f1a..3bb80db51562 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1494,13 +1494,13 @@ unsigned int OnAssocReq(struct adapter *padapter, union recv_frame *precv_frame) } /* save HT capabilities in the sta object */ - memset(&pstat->htpriv.ht_cap, 0, sizeof(struct rtw_ieee80211_ht_cap)); - if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct rtw_ieee80211_ht_cap)) { + memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap)); + if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap)) { pstat->flags |= WLAN_STA_HT; pstat->flags |= WLAN_STA_WME; - memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct rtw_ieee80211_ht_cap)); + memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap)); } else pstat->flags &= ~WLAN_STA_HT; @@ -5348,7 +5348,7 @@ void update_sta_info(struct adapter *padapter, struct sta_info *psta) psta->htpriv.stbc_cap = pmlmepriv->htpriv.stbc_cap; psta->htpriv.beamform_cap = pmlmepriv->htpriv.beamform_cap; - memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct rtw_ieee80211_ht_cap)); + memcpy(&psta->htpriv.ht_cap, &pmlmeinfo->HT_caps, sizeof(struct ieee80211_ht_cap)); } else { psta->htpriv.ht_option = false; diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index eda91b78a543..c9ac5c685d74 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -1233,7 +1233,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) u32 wpa_ielen = 0; u8 *pbssid = GetAddr3Ptr(pframe); struct HT_info_element *pht_info = NULL; - struct rtw_ieee80211_ht_cap *pht_cap = NULL; + struct ieee80211_ht_cap *pht_cap = NULL; u32 bcn_channel; unsigned short ht_cap_info; unsigned char ht_info_infos_0; @@ -1282,7 +1282,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) /* parsing HT_CAP_IE */ p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); if (p && len > 0) { - pht_cap = (struct rtw_ieee80211_ht_cap *)(p + 2); + pht_cap = (struct ieee80211_ht_cap *)(p + 2); ht_cap_info = le16_to_cpu(pht_cap->cap_info); } else { ht_cap_info = 0; diff --git a/drivers/staging/rtl8723bs/hal/hal_com.c b/drivers/staging/rtl8723bs/hal/hal_com.c index 02676da5c166..16b259acbe1a 100644 --- a/drivers/staging/rtl8723bs/hal/hal_com.c +++ b/drivers/staging/rtl8723bs/hal/hal_com.c @@ -989,7 +989,7 @@ void rtw_hal_update_sta_rate_mask(struct adapter *padapter, struct sta_info *pst limit = 8; /* 1R */ for (i = 0; i < limit; i++) { - if (psta->htpriv.ht_cap.supp_mcs_set[i/8] & BIT(i%8)) + if (psta->htpriv.ht_cap.mcs.rx_mask[i/8] & BIT(i%8)) tx_ra_bitmap |= BIT(i+12); } } diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index 5cd307cb48a5..e2a6b92ba3ba 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -232,7 +232,7 @@ struct ieee_param { u16 capability; int flags; u8 tx_supp_rates[16]; - struct rtw_ieee80211_ht_cap ht_cap; + struct ieee80211_ht_cap ht_cap; } add_sta; struct { u8 reserved[2];/* for set max_num_sta */ @@ -254,7 +254,7 @@ struct sta_data { u32 sta_set; u8 tx_supp_rates[16]; u32 tx_supp_rates_len; - struct rtw_ieee80211_ht_cap ht_cap; + struct ieee80211_ht_cap ht_cap; u64 rx_pkts; u64 rx_bytes; u64 rx_drops; diff --git a/drivers/staging/rtl8723bs/include/rtw_ht.h b/drivers/staging/rtl8723bs/include/rtw_ht.h index 13489913f40b..a72f51031f89 100644 --- a/drivers/staging/rtl8723bs/include/rtw_ht.h +++ b/drivers/staging/rtl8723bs/include/rtw_ht.h @@ -33,7 +33,7 @@ struct ht_priv { u8 stbc_cap; u8 beamform_cap; - struct rtw_ieee80211_ht_cap ht_cap; + struct ieee80211_ht_cap ht_cap; }; diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h index 3a7dd2ed26a8..6f2d4ea51f15 100644 --- a/drivers/staging/rtl8723bs/include/wifi.h +++ b/drivers/staging/rtl8723bs/include/wifi.h @@ -657,22 +657,6 @@ struct rtw_ieee80211_bar { __le16 start_seq_num; } __attribute__((packed)); - /** - * struct rtw_ieee80211_ht_cap - HT capabilities - * - * This structure refers to "HT capabilities element" as - * described in 802.11n draft section 7.3.2.52 - */ - -struct rtw_ieee80211_ht_cap { - __le16 cap_info; - unsigned char ampdu_params_info; - unsigned char supp_mcs_set[16]; - __le16 extended_ht_cap_info; - __le16 tx_BF_cap_info; - unsigned char antenna_selection_info; -} __attribute__ ((packed)); - /** * struct rtw_ieee80211_ht_cap - HT additional information * diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 3f3eab3d879a..783daa30f1d7 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -114,10 +114,10 @@ static char *translate_scan(struct adapter *padapter, p = rtw_get_ie(&pnetwork->network.IEs[12], _HT_CAPABILITY_IE_, &ht_ielen, pnetwork->network.IELength-12); } if (p && ht_ielen > 0) { - struct rtw_ieee80211_ht_cap *pht_capie; + struct ieee80211_ht_cap *pht_capie; ht_cap = true; - pht_capie = (struct rtw_ieee80211_ht_cap *)(p+2); - memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2); + pht_capie = (struct ieee80211_ht_cap *)(p+2); + memcpy(&mcs_rate, pht_capie->mcs.rx_mask, 2); bw_40MHz = (le16_to_cpu(pht_capie->cap_info) & IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0; short_GI = (le16_to_cpu(pht_capie->cap_info) & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; } @@ -3793,7 +3793,7 @@ static int rtw_add_sta(struct net_device *dev, struct ieee_param *param) if (WLAN_STA_HT&flags) { psta->htpriv.ht_option = true; psta->qos_option = 1; - memcpy((void *)&psta->htpriv.ht_cap, (void *)¶m->u.add_sta.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); + memcpy((void *)&psta->htpriv.ht_cap, (void *)¶m->u.add_sta.ht_cap, sizeof(struct ieee80211_ht_cap)); } else { psta->htpriv.ht_option = false; } @@ -3906,7 +3906,7 @@ static int rtw_ioctl_get_sta_data(struct net_device *dev, struct ieee_param *par psta_data->tx_supp_rates_len = psta->bssratelen; memcpy(psta_data->tx_supp_rates, psta->bssrateset, psta->bssratelen); - memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct rtw_ieee80211_ht_cap)); + memcpy(&psta_data->ht_cap, &psta->htpriv.ht_cap, sizeof(struct ieee80211_ht_cap)); psta_data->rx_pkts = psta->sta_stats.rx_data_pkts; psta_data->rx_bytes = psta->sta_stats.rx_bytes; psta_data->rx_drops = psta->sta_stats.rx_drops; -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:52 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:52 -0600 Subject: [PATCH 7/9] staging: rtl8723bs: replace rtw_ieee80211_spectrum_mgmt_actioncode In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-7-ross.schm.dev@gmail.com> Replace the unique rtw_ieee80211_mgmt_actioncode enum with the provided standard ieee80211_spectrum_mgmt_actioncode. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 10 +++++----- drivers/staging/rtl8723bs/include/ieee80211.h | 10 ---------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 3bb80db51562..cdb1d2b06f1b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1891,11 +1891,11 @@ unsigned int on_action_spct(struct adapter *padapter, union recv_frame *precv_fr action = frame_body[1]; switch (action) { - case RTW_WLAN_ACTION_SPCT_MSR_REQ: - case RTW_WLAN_ACTION_SPCT_MSR_RPRT: - case RTW_WLAN_ACTION_SPCT_TPC_REQ: - case RTW_WLAN_ACTION_SPCT_TPC_RPRT: - case RTW_WLAN_ACTION_SPCT_CHL_SWITCH: + case WLAN_ACTION_SPCT_MSR_REQ: + case WLAN_ACTION_SPCT_MSR_RPRT: + case WLAN_ACTION_SPCT_TPC_REQ: + case WLAN_ACTION_SPCT_TPC_RPRT: + case WLAN_ACTION_SPCT_CHL_SWITCH: break; default: break; diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index e2a6b92ba3ba..06aacafd2340 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -893,16 +893,6 @@ enum rtw_ieee80211_category { RTW_WLAN_CATEGORY_P2P = 0x7f,/* P2P action frames */ }; -/* SPECTRUM_MGMT action code */ -enum rtw_ieee80211_spectrum_mgmt_actioncode { - RTW_WLAN_ACTION_SPCT_MSR_REQ = 0, - RTW_WLAN_ACTION_SPCT_MSR_RPRT = 1, - RTW_WLAN_ACTION_SPCT_TPC_REQ = 2, - RTW_WLAN_ACTION_SPCT_TPC_RPRT = 3, - RTW_WLAN_ACTION_SPCT_CHL_SWITCH = 4, - RTW_WLAN_ACTION_SPCT_EXT_CHL_SWITCH = 5, -}; - enum _PUBLIC_ACTION { ACT_PUBLIC_BSSCOEXIST = 0, /* 20/40 BSS Coexistence */ ACT_PUBLIC_DSE_ENABLE = 1, -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:53 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:53 -0600 Subject: [PATCH 8/9] staging: rtl8723bs: replace rtw_ieee80211_ht_actioncode In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-8-ross.schm.dev@gmail.com> Replace the unique rtw_ieee80211_ht_actioncode enum with the provided standard ieee80211_ht_actioncode. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 2 +- drivers/staging/rtl8723bs/include/ieee80211.h | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index cdb1d2b06f1b..c113902877bd 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -2145,7 +2145,7 @@ unsigned int OnAction_ht(struct adapter *padapter, union recv_frame *precv_frame action = frame_body[1]; switch (action) { - case RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING: + case WLAN_HT_ACTION_COMPRESSED_BF: break; default: break; diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index 06aacafd2340..cd8f6d006a38 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -920,18 +920,6 @@ enum rtw_ieee80211_back_actioncode { RTW_WLAN_ACTION_DELBA = 2, }; -/* HT features action code */ -enum rtw_ieee80211_ht_actioncode { - RTW_WLAN_ACTION_HT_NOTI_CHNL_WIDTH = 0, - RTW_WLAN_ACTION_HT_SM_PS = 1, - RTW_WLAN_ACTION_HT_PSMP = 2, - RTW_WLAN_ACTION_HT_SET_PCO_PHASE = 3, - RTW_WLAN_ACTION_HT_CSI = 4, - RTW_WLAN_ACTION_HT_NON_COMPRESS_BEAMFORMING = 5, - RTW_WLAN_ACTION_HT_COMPRESS_BEAMFORMING = 6, - RTW_WLAN_ACTION_HT_ASEL_FEEDBACK = 7, -}; - /* BACK (block-ack) parties */ enum rtw_ieee80211_back_parties { RTW_WLAN_BACK_RECIPIENT = 0, -- 2.25.1 From ross.schm.dev at gmail.com Thu Nov 5 03:47:54 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Wed, 4 Nov 2020 21:47:54 -0600 Subject: [PATCH 9/9] staging: rtl8723bs: replace ieee80211_back_actioncode In-Reply-To: <20201105034754.12383-1-ross.schm.dev@gmail.com> References: <20201105034754.12383-1-ross.schm.dev@gmail.com> Message-ID: <20201105034754.12383-9-ross.schm.dev@gmail.com> Replace the unique rtw_ieee80211_back_actioncode with the standard provided ieee80211_back_actioncode. Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 16 ++++++++-------- drivers/staging/rtl8723bs/include/ieee80211.h | 7 ------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index c113902877bd..1a6cae5f9895 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1944,21 +1944,21 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra action = frame_body[1]; DBG_871X("%s, action =%d\n", __func__, action); switch (action) { - case RTW_WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ + case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */ memcpy(&(pmlmeinfo->ADDBA_req), &(frame_body[2]), sizeof(struct ADDBA_request)); /* process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), GetAddr3Ptr(pframe)); */ process_addba_req(padapter, (u8 *)&(pmlmeinfo->ADDBA_req), addr); if (pmlmeinfo->accept_addba_req) { - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 0); + issue_action_BA(padapter, addr, WLAN_ACTION_ADDBA_RESP, 0); } else { - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ + issue_action_BA(padapter, addr, WLAN_ACTION_ADDBA_RESP, 37);/* reject ADDBA Req */ } break; - case RTW_WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ + case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */ status = get_unaligned_le16(&frame_body[3]); tid = ((frame_body[5] >> 2) & 0x7); @@ -1981,7 +1981,7 @@ unsigned int OnAction_back(struct adapter *padapter, union recv_frame *precv_fra /* DBG_871X("marc: ADDBA RSP: %x\n", pmlmeinfo->agg_enable_bitmap); */ break; - case RTW_WLAN_ACTION_DELBA: /* DELBA */ + case WLAN_ACTION_DELBA: /* DELBA */ if ((frame_body[3] & BIT(3)) == 0) { psta->htpriv.agg_enable_bitmap &= ~BIT((frame_body[3] >> 4) & 0xf); @@ -4199,7 +4199,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) for (tid = 0; tid < MAXTID; tid++) { if (psta->recvreorder_ctrl[tid].enable) { DBG_871X("rx agg disable tid(%d)\n", tid); - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); + issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); psta->recvreorder_ctrl[tid].enable = false; psta->recvreorder_ctrl[tid].indicate_seq = 0xffff; #ifdef DBG_RX_SEQ @@ -4213,7 +4213,7 @@ unsigned int send_delba(struct adapter *padapter, u8 initiator, u8 *addr) for (tid = 0; tid < MAXTID; tid++) { if (psta->htpriv.agg_enable_bitmap & BIT(tid)) { DBG_871X("tx agg disable tid(%d)\n", tid); - issue_action_BA(padapter, addr, RTW_WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); + issue_action_BA(padapter, addr, WLAN_ACTION_DELBA, (((tid << 1) | initiator)&0x1F)); psta->htpriv.agg_enable_bitmap &= ~BIT(tid); psta->htpriv.candidate_tid_bitmap &= ~BIT(tid); @@ -6529,7 +6529,7 @@ u8 add_ba_hdl(struct adapter *padapter, unsigned char *pbuf) /* pmlmeinfo->ADDBA_retry_count = 0; */ /* pmlmeinfo->candidate_tid_bitmap |= (0x1 << pparm->tid); */ /* psta->htpriv.candidate_tid_bitmap |= BIT(pparm->tid); */ - issue_action_BA(padapter, pparm->addr, RTW_WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); + issue_action_BA(padapter, pparm->addr, WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid); /* _set_timer(&pmlmeext->ADDBA_timer, ADDBA_TO); */ _set_timer(&psta->addba_retry_timer, ADDBA_TO); } else { diff --git a/drivers/staging/rtl8723bs/include/ieee80211.h b/drivers/staging/rtl8723bs/include/ieee80211.h index cd8f6d006a38..bf53d850c370 100644 --- a/drivers/staging/rtl8723bs/include/ieee80211.h +++ b/drivers/staging/rtl8723bs/include/ieee80211.h @@ -913,13 +913,6 @@ enum _PUBLIC_ACTION { ACT_PUBLIC_MAX }; -/* BACK action code */ -enum rtw_ieee80211_back_actioncode { - RTW_WLAN_ACTION_ADDBA_REQ = 0, - RTW_WLAN_ACTION_ADDBA_RESP = 1, - RTW_WLAN_ACTION_DELBA = 2, -}; - /* BACK (block-ack) parties */ enum rtw_ieee80211_back_parties { RTW_WLAN_BACK_RECIPIENT = 0, -- 2.25.1 From zhangqilong3 at huawei.com Thu Nov 5 08:06:58 2020 From: zhangqilong3 at huawei.com (zhangqilong) Date: Thu, 5 Nov 2020 08:06:58 +0000 Subject: =?gb2312?B?tPC4tDogW1BBVENIIC1uZXh0XSBtZWRpYTogY2VkcnVzOiBmaXggcmVmZXJl?= =?gb2312?B?bmNlIGxlYWsgaW4gY2VkcnVzX3N0YXJ0X3N0cmVhbWluZw==?= In-Reply-To: <2eb14a6d-4680-1527-0985-fd371e3ba2e8@xs4all.nl> References: <20201102142622.140001-1-zhangqilong3@huawei.com> <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> <2eb14a6d-4680-1527-0985-fd371e3ba2e8@xs4all.nl> Message-ID: <710479d756b14da591bb2342a1767242@huawei.com> > On 02/11/2020 15:18, Maxime Ripard wrote: > > On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: > >> pm_runtime_get_sync will increment pm usage counter even it failed. > >> Forgetting to pm_runtime_put_noidle will result in reference leak in > >> cedrus_start_streaming. We should fix it. > >> > >> Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") > >> Signed-off-by: Zhang Qilong > > > > Shouldn't we fix pm_runtime_get_sync instead then? It seems that most > > of the callers get this wrong, and that's definitely non-obvious. > > It's been discussed before, but nobody stepped up to address this issue. In the > end I decided to just accept media patches that fix this in the drivers rather > than waiting for some mythical future core fix. > > Nor do I think that you can just 'fix' pm_runtime_get_sync, since then you will > get cases where pm_runtime_put is called once too often. > Thanks for your nice comment, if any updates occur about pm_runtime_get_sync, I will pay attention to it. Thanks, best wish, Zhang Qilong > Regards, > > Hans > > > > > Maxime > > From sakari.ailus at linux.intel.com Thu Nov 5 08:45:56 2020 From: sakari.ailus at linux.intel.com (Sakari Ailus) Date: Thu, 5 Nov 2020 10:45:56 +0200 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201023174546.504028-9-paul.kocialkowski@bootlin.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> Message-ID: <20201105084556.GZ26150@paasikivi.fi.intel.com> Hi Paul, On Fri, Oct 23, 2020 at 07:45:40PM +0200, Paul Kocialkowski wrote: > The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > found on Allwinner SoCs such as the A31 and V3/V3s. > > It is a standalone block, connected to the CSI controller on one side > and to the MIPI D-PHY block on the other. It has a dedicated address > space, interrupt line and clock. > > Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > controller (CSI0) but newer SoCs (such as the V5) may allow switching > MIPI CSI-2 controllers between CSI controllers. > > It is represented as a V4L2 subdev to the CSI controller and takes a > MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > media controller API. > > Signed-off-by: Paul Kocialkowski > --- > drivers/media/platform/sunxi/Kconfig | 1 + > drivers/media/platform/sunxi/Makefile | 1 + > .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 ++++++++++++++++++ > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 ++++ > 6 files changed, 768 insertions(+) > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig > index 7151cc249afa..9684e07454ad 100644 > --- a/drivers/media/platform/sunxi/Kconfig > +++ b/drivers/media/platform/sunxi/Kconfig > @@ -2,3 +2,4 @@ > > source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" > source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" > +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" > diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile > index fc537c9f5ca9..887a7cae8fca 100644 > --- a/drivers/media/platform/sunxi/Makefile > +++ b/drivers/media/platform/sunxi/Makefile > @@ -2,5 +2,6 @@ > > obj-y += sun4i-csi/ > obj-y += sun6i-csi/ > +obj-y += sun6i-mipi-csi2/ > obj-y += sun8i-di/ > obj-y += sun8i-rotate/ > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > new file mode 100644 > index 000000000000..7033bda483b4 > --- /dev/null > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > @@ -0,0 +1,11 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +config VIDEO_SUN6I_MIPI_CSI2 > + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" > + depends on VIDEO_V4L2 && COMMON_CLK > + depends on ARCH_SUNXI || COMPILE_TEST > + select MEDIA_CONTROLLER > + select VIDEO_V4L2_SUBDEV_API > + select REGMAP_MMIO > + select V4L2_FWNODE > + help > + Support for the Allwinner A31 MIPI CSI-2 Controller. > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > new file mode 100644 > index 000000000000..14e4e03818b5 > --- /dev/null > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > @@ -0,0 +1,4 @@ > +# SPDX-License-Identifier: GPL-2.0-only > +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o > + > +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > new file mode 100644 > index 000000000000..ce89c35f5b86 > --- /dev/null > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > @@ -0,0 +1,635 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright 2020 Bootlin > + * Author: Paul Kocialkowski > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "sun6i_mipi_csi2.h" > + > +#define MODULE_NAME "sun6i-mipi-csi2" > + > +/* Core */ > + > +static irqreturn_t sun6i_mipi_csi2_isr(int irq, void *dev_id) > +{ > + struct sun6i_mipi_csi2_dev *cdev = (struct sun6i_mipi_csi2_dev *)dev_id; Unnecessary casting from void *. > + struct regmap *regmap = cdev->regmap; > + u32 pending; > + > + WARN_ONCE(1, MODULE_NAME > + ": Unsolicited interrupt, an error likely occurred!\n"); > + > + regmap_read(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, &pending); > + regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, pending); > + > + /* > + * The interrupt can be used to catch transmission errors. > + * However, we currently lack plumbing for reporting that to the > + * A31 CSI controller driver. > + */ > + > + return IRQ_HANDLED; > +} > + > +static int sun6i_mipi_csi2_s_power(struct v4l2_subdev *subdev, int on) Please use runtime PM instead. > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > + int ret; > + > + if (!on) { > + clk_disable_unprepare(cdev->clk_mod); > + reset_control_assert(cdev->reset); > + > + return 0; > + } > + > + ret = clk_prepare_enable(cdev->clk_mod); > + if (ret) { > + dev_err(cdev->dev, "failed to enable module clock\n"); > + return ret; > + } > + > + ret = reset_control_deassert(cdev->reset); > + if (ret) { > + dev_err(cdev->dev, "failed to deassert reset\n"); > + goto error_clk; > + } > + > + return 0; > + > +error_clk: > + clk_disable_unprepare(cdev->clk_mod); > + > + return ret; > +} > + > +static const struct v4l2_subdev_core_ops sun6i_mipi_csi2_subdev_core_ops = { > + .s_power = sun6i_mipi_csi2_s_power, > +}; > + > +/* Video */ > + > +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > + struct v4l2_subdev *remote_subdev = video->remote_subdev; > + struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = > + &video->endpoint.bus.mipi_csi2; > + union phy_configure_opts dphy_opts = { 0 }; > + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; > + struct regmap *regmap = cdev->regmap; > + struct v4l2_ctrl *ctrl; > + unsigned int lanes_count; > + unsigned int bpp; > + unsigned long pixel_rate; > + u8 data_type = 0; > + u32 version = 0; > + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ > + int ret = 0; > + > + if (!remote_subdev) > + return -ENODEV; > + > + if (!on) { > + v4l2_subdev_call(remote_subdev, video, s_stream, 0); > + > +disable: I think this label would be nicer at the end of the function (so you'd have a goto here). > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > + SUN6I_MIPI_CSI2_CTL_EN, 0); > + > + phy_power_off(cdev->dphy); > + > + return ret; > + } > + > + switch (video->mbus_code) { > + case MEDIA_BUS_FMT_SBGGR8_1X8: > + case MEDIA_BUS_FMT_SGBRG8_1X8: > + case MEDIA_BUS_FMT_SGRBG8_1X8: > + case MEDIA_BUS_FMT_SRGGB8_1X8: > + data_type = MIPI_CSI2_DATA_TYPE_RAW8; > + bpp = 8; > + break; > + case MEDIA_BUS_FMT_SBGGR10_1X10: > + case MEDIA_BUS_FMT_SGBRG10_1X10: > + case MEDIA_BUS_FMT_SGRBG10_1X10: > + case MEDIA_BUS_FMT_SRGGB10_1X10: > + data_type = MIPI_CSI2_DATA_TYPE_RAW10; > + bpp = 10; > + break; > + default: > + return -EINVAL; > + } > + > + /* Sensor pixel rate */ > + > + ctrl = v4l2_ctrl_find(remote_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); > + if (!ctrl) { > + dev_err(cdev->dev, > + "%s: no MIPI CSI-2 pixel rate from the sensor\n", > + __func__); > + return -ENODEV; > + } > + > + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); > + if (!pixel_rate) { > + dev_err(cdev->dev, > + "%s: zero MIPI CSI-2 pixel rate from the sensor\n", > + __func__); > + return -ENODEV; > + } > + > + /* D-PHY configuration */ > + > + lanes_count = bus_mipi_csi2->num_data_lanes; > + phy_mipi_dphy_get_default_config(pixel_rate, bpp, lanes_count, > + dphy_cfg); > + > + > + /* > + * Note that our hardware is using DDR, which is not taken in account by > + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from > + * the pixel rate, lanes count and bpp. > + * > + * The resulting clock rate is basically the symbol rate over the whole > + * link. The actual clock rate is calculated with division by two since > + * DDR samples both on rising and falling edges. > + */ > + > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 config:\n"); > + dev_dbg(cdev->dev, "%ld pixels/s, %u bits/pixel, %lu Hz clock\n", > + pixel_rate, bpp, dphy_cfg->hs_clk_rate / 2); > + > + ret = 0; > + ret |= phy_reset(cdev->dphy); > + ret |= phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, > + PHY_MIPI_DPHY_SUBMODE_RX); > + ret |= phy_configure(cdev->dphy, &dphy_opts); Huh. Please don't do bitwise or operations on error codes. > + > + if (ret) { > + dev_err(cdev->dev, "failed to setup MIPI D-PHY\n"); > + return ret; > + } > + > + ret = phy_power_on(cdev->dphy); > + if (ret) { > + dev_err(cdev->dev, "failed to power on MIPI D-PHY\n"); > + return ret; > + } > + > + /* MIPI CSI-2 controller setup */ > + > + /* > + * The enable flow in the Allwinner BSP is a bit different: the enable > + * and reset bits are set together before starting the CSI controller. > + * > + * In mainline we enable the CSI controller first (due to subdev logic). > + * One reliable way to make this work is to deassert reset, configure > + * registers and enable the controller when everything's ready. > + * > + * However, reading the version appears necessary for it to work > + * reliably. Replacing it with a delay doesn't do the trick. > + */ > + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, > + SUN6I_MIPI_CSI2_CTL_RESET_N | > + SUN6I_MIPI_CSI2_CTL_VERSION_EN | > + SUN6I_MIPI_CSI2_CTL_UNPK_EN); > + > + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); > + > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); > + > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 version: %04x\n", version); > + > + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, > + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | > + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); > + > + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | > + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); > + > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); > + > + ret = v4l2_subdev_call(remote_subdev, video, s_stream, 1); > + if (ret) > + goto disable; > + > + return 0; > +} > + > +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_subdev_video_ops = { > + .s_stream = sun6i_mipi_csi2_s_stream, > +}; > + > +/* Pad */ > + > +static int sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, > + struct v4l2_subdev_pad_config *config, > + struct v4l2_subdev_mbus_code_enum *code_enum) You can easily get under 80 characters per line if you wrap after the function's return type. > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + > + if (!video->remote_subdev) > + return -ENODEV; > + > + /* Forward to the sensor. */ > + code_enum->pad = video->remote_pad_index; > + > + return v4l2_subdev_call(video->remote_subdev, pad, enum_mbus_code, > + config, code_enum); > +} > + > +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, > + struct v4l2_subdev_pad_config *config, > + struct v4l2_subdev_format *format) > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + > + if (!video->remote_subdev) > + return -ENODEV; > + > + /* Forward to the sensor. */ > + format->pad = video->remote_pad_index; > + > + return v4l2_subdev_call(video->remote_subdev, pad, get_fmt, config, > + format); The entity this driver controls is independent of the upstream device in its configuratione, you should not try to propagate the configuration upstream in the pipeline. The same applies to other similar functions in the driver. > +} > + > +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, > + struct v4l2_subdev_pad_config *config, > + struct v4l2_subdev_format *format) > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + > + if (!video->remote_subdev) > + return -ENODEV; > + > + /* Forward to the sensor. */ > + format->pad = video->remote_pad_index; > + > + return v4l2_subdev_call(video->remote_subdev, pad, set_fmt, config, > + format); > +} > + > +static int sun6i_mipi_csi2_enum_frame_size(struct v4l2_subdev *subdev, > + struct v4l2_subdev_pad_config *config, > + struct v4l2_subdev_frame_size_enum *size_enum) > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + > + if (!video->remote_subdev) > + return -ENODEV; > + > + /* Forward to the sensor. */ > + size_enum->pad = video->remote_pad_index; > + > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_size, > + config, size_enum); > +} > + > +static int sun6i_mipi_csi2_enum_frame_interval(struct v4l2_subdev *subdev, > + struct v4l2_subdev_pad_config *config, > + struct v4l2_subdev_frame_interval_enum *interval_enum) > +{ > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + > + if (!video->remote_subdev) > + return -ENODEV; > + > + /* Forward to the sensor. */ > + interval_enum->pad = video->remote_pad_index; > + > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_interval, > + config, interval_enum); > +} > + > +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { > + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, > + .get_fmt = sun6i_mipi_csi2_get_fmt, > + .set_fmt = sun6i_mipi_csi2_set_fmt, > + .enum_frame_size = sun6i_mipi_csi2_enum_frame_size, > + .enum_frame_interval = sun6i_mipi_csi2_enum_frame_interval, > +}; > + > +/* Subdev */ > + > +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { > + .core = &sun6i_mipi_csi2_subdev_core_ops, > + .video = &sun6i_mipi_csi2_subdev_video_ops, > + .pad = &sun6i_mipi_csi2_subdev_pad_ops, > +}; > + > +/* Notifier */ > + > +static int sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, > + struct v4l2_subdev *remote_subdev, > + struct v4l2_async_subdev *remote_subdev_async) > +{ > + struct v4l2_subdev *subdev = notifier->sd; > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > + int source_pad; > + int ret; > + > + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, > + remote_subdev->fwnode, > + MEDIA_PAD_FL_SOURCE); > + if (source_pad < 0) > + return source_pad; > + > + ret = media_create_pad_link(&remote_subdev->entity, source_pad, > + &subdev->entity, 0, > + MEDIA_LNK_FL_ENABLED | > + MEDIA_LNK_FL_IMMUTABLE); > + if (ret) { > + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", > + remote_subdev->entity.name, source_pad, > + subdev->entity.name, 0); > + return ret; > + } > + > + video->remote_subdev = remote_subdev; > + video->remote_pad_index = source_pad; > + > + return 0; > +} > + > +static const struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { > + .bound = sun6i_mipi_csi2_notifier_bound, > +}; > + > +/* Media Entity */ > + > +static int sun6i_mipi_csi2_link_validate(struct media_link *link) > +{ > + struct v4l2_subdev *subdev = > + container_of(link->sink->entity, struct v4l2_subdev, entity); > + struct sun6i_mipi_csi2_video *video = > + sun6i_mipi_csi2_subdev_video(subdev); > + struct v4l2_subdev *remote_subdev; > + struct v4l2_subdev_format format = { 0 }; > + int ret; > + > + if (!is_media_entity_v4l2_subdev(link->source->entity)) > + return -EINVAL; > + > + remote_subdev = media_entity_to_v4l2_subdev(link->source->entity); > + > + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; > + format.pad = link->source->index; > + > + ret = v4l2_subdev_call(remote_subdev, pad, get_fmt, NULL, &format); > + if (ret) > + return ret; > + > + video->mbus_code = format.format.code; > + > + return 0; > +} > + > +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { > + .link_validate = sun6i_mipi_csi2_link_validate, > +}; > + > +/* Base Driver */ > + > +static int sun6i_mipi_csi2_v4l2_setup(struct sun6i_mipi_csi2_dev *cdev) > +{ > + struct sun6i_mipi_csi2_video *video = &cdev->video; > + struct v4l2_subdev *subdev = &video->subdev; > + struct v4l2_async_notifier *notifier = &video->notifier; > + struct fwnode_handle *handle; > + struct v4l2_fwnode_endpoint *endpoint; > + int ret; > + > + /* Subdev */ > + > + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); > + subdev->dev = cdev->dev; > + strscpy(subdev->name, MODULE_NAME, sizeof(subdev->name)); > + v4l2_set_subdevdata(subdev, cdev); > + > + /* Entity */ > + > + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; > + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; Why is there no device node? This driver appears to be MC-enabled. > + > + /* Pads */ > + > + video->pads[0].flags = MEDIA_PAD_FL_SINK; > + video->pads[1].flags = MEDIA_PAD_FL_SOURCE; > + > + ret = media_entity_pads_init(&subdev->entity, 2, video->pads); > + if (ret) > + return ret; > + > + /* Endpoint */ > + > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(cdev->dev), 0, 0, > + FWNODE_GRAPH_ENDPOINT_NEXT); > + if (!handle) > + goto error_media_entity; > + > + endpoint = &video->endpoint; > + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; > + > + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); > + fwnode_handle_put(handle); > + if (ret) > + goto error_media_entity; > + > + /* Notifier */ > + > + v4l2_async_notifier_init(notifier); > + > + ret = v4l2_async_notifier_add_fwnode_remote_subdev(notifier, handle, > + &video->subdev_async); > + if (ret) > + goto error_media_entity; > + > + video->notifier.ops = &sun6i_mipi_csi2_notifier_ops; > + > + ret = v4l2_async_subdev_notifier_register(subdev, notifier); > + if (ret < 0) > + goto error_notifier; > + > + /* Subdev */ > + > + ret = v4l2_async_register_subdev(subdev); > + if (ret < 0) > + goto error_notifier_registered; > + > + return 0; > + > +error_notifier_registered: > + v4l2_async_notifier_unregister(notifier); > +error_notifier: > + v4l2_async_notifier_cleanup(notifier); > +error_media_entity: > + media_entity_cleanup(&subdev->entity); > + > + return ret; > +} > + > +static int sun6i_mipi_csi2_v4l2_teardown(struct sun6i_mipi_csi2_dev *cdev) > +{ > + struct sun6i_mipi_csi2_video *video = &cdev->video; > + struct v4l2_subdev *subdev = &video->subdev; > + struct v4l2_async_notifier *notifier = &video->notifier; > + > + v4l2_async_unregister_subdev(subdev); > + v4l2_async_notifier_unregister(notifier); > + v4l2_async_notifier_cleanup(notifier); > + media_entity_cleanup(&subdev->entity); > + v4l2_device_unregister_subdev(subdev); > + > + return 0; > +} > + > +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > + .max_register = 0x400, > +}; > + > +static int sun6i_mipi_csi2_resource_request(struct sun6i_mipi_csi2_dev *cdev, > + struct platform_device *pdev) > +{ > + struct resource *res; > + void __iomem *io_base; > + int irq; > + int ret; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + io_base = devm_ioremap_resource(&pdev->dev, res); > + if (IS_ERR(io_base)) > + return PTR_ERR(io_base); > + > + cdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, > + &sun6i_mipi_csi2_regmap_config); > + if (IS_ERR(cdev->regmap)) { > + dev_err(&pdev->dev, "failed to init register map\n"); > + return PTR_ERR(cdev->regmap); > + } > + > + cdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); > + if (IS_ERR(cdev->clk_mod)) { > + dev_err(&pdev->dev, "failed to acquire csi clock\n"); > + return PTR_ERR(cdev->clk_mod); > + } > + > + cdev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); > + if (IS_ERR(cdev->reset)) { > + dev_err(&pdev->dev, "failed to get reset controller\n"); > + return PTR_ERR(cdev->reset); > + } > + > + irq = platform_get_irq(pdev, 0); > + if (irq < 0) > + return -ENXIO; > + > + ret = devm_request_irq(&pdev->dev, irq, sun6i_mipi_csi2_isr, 0, > + MODULE_NAME, cdev); > + if (ret) { > + dev_err(&pdev->dev, "failed to request MIPI CSI-2 IRQ\n"); > + return ret; > + } > + > + cdev->dphy = devm_phy_get(&pdev->dev, "dphy"); > + if (IS_ERR(cdev->dphy)) { > + dev_err(&pdev->dev, "failed to get the MIPI D-PHY\n"); > + return PTR_ERR(cdev->dphy); > + } > + > + ret = phy_init(cdev->dphy); > + if (ret) { > + dev_err(&pdev->dev, "failed to initialize the MIPI D-PHY\n"); > + return ret; > + } > + > + return 0; > +} > + > +static int sun6i_mipi_csi2_probe(struct platform_device *pdev) > +{ > + struct sun6i_mipi_csi2_dev *cdev; > + int ret; > + > + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); > + if (!cdev) > + return -ENOMEM; > + > + cdev->dev = &pdev->dev; > + > + ret = sun6i_mipi_csi2_resource_request(cdev, pdev); > + if (ret) > + return ret; > + > + platform_set_drvdata(pdev, cdev); > + > + ret = sun6i_mipi_csi2_v4l2_setup(cdev); > + if (ret) > + return ret; > + > + return 0; > +} > + > +static int sun6i_mipi_csi2_remove(struct platform_device *pdev) > +{ > + struct sun6i_mipi_csi2_dev *cdev = platform_get_drvdata(pdev); > + > + phy_exit(cdev->dphy); > + > + return sun6i_mipi_csi2_v4l2_teardown(cdev); > +} > + > +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { > + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, > + { .compatible = "allwinner,sun8i-v3s-mipi-csi2", }, > + {}, > +}; > +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); > + > +static struct platform_driver sun6i_mipi_csi2_platform_driver = { > + .probe = sun6i_mipi_csi2_probe, > + .remove = sun6i_mipi_csi2_remove, > + .driver = { > + .name = MODULE_NAME, > + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), > + }, > +}; > +module_platform_driver(sun6i_mipi_csi2_platform_driver); > + > +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); > +MODULE_AUTHOR("Paul Kocialkowski "); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > new file mode 100644 > index 000000000000..f3cce99bfd44 > --- /dev/null > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > @@ -0,0 +1,116 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright 2020 Bootlin > + * Author: Paul Kocialkowski > + */ > + > +#ifndef __SUN6I_MIPI_CSI2_H__ > +#define __SUN6I_MIPI_CSI2_H__ > + > +#include > +#include > +#include > +#include > +#include > + > +#define SUN6I_MIPI_CSI2_CTL_REG 0x0 > +#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31) > +#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30) > +#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1) > +#define SUN6I_MIPI_CSI2_CTL_EN BIT(0) > +#define SUN6I_MIPI_CSI2_CFG_REG 0x4 > +#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \ > + GENMASK(9, 8)) > +#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0)) > +#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8 > +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ > + ((ch) * 8 + 6)) > +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ > + ((ch) * 8)) > +#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc > + > +#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c > + > +#define SUN6I_MIPI_CSI2_CH_BASE 0x1000 > +#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100 > + > +#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40 > +#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50 > +#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8) > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0) > + > +#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58 > +#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8) > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0) > + > +#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60 > +#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70 > +#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74 > +#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78 > +#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c > +#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80 > + > +#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \ > + (SUN6I_MIPI_CSI2_CH_BASE + SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg)) > + > +enum mipi_csi2_data_type { > + MIPI_CSI2_DATA_TYPE_RAW8 = 0x2a, > + MIPI_CSI2_DATA_TYPE_RAW10 = 0x2b, > + MIPI_CSI2_DATA_TYPE_RAW12 = 0x2c, > +}; > + > +struct sun6i_mipi_csi2_video { > + struct v4l2_fwnode_endpoint endpoint; > + struct v4l2_subdev subdev; > + struct media_pad pads[2]; > + > + struct v4l2_async_subdev subdev_async; > + struct v4l2_async_notifier notifier; > + > + struct v4l2_subdev *remote_subdev; > + u32 remote_pad_index; > + u32 mbus_code; > +}; > + > +struct sun6i_mipi_csi2_dev { > + struct device *dev; > + > + struct regmap *regmap; > + struct clk *clk_mod; > + struct reset_control *reset; > + struct phy *dphy; > + > + struct sun6i_mipi_csi2_video video; > +}; > + > +#define sun6i_mipi_csi2_subdev_video(subdev) \ > + container_of(subdev, struct sun6i_mipi_csi2_video, subdev) > + > +#define sun6i_mipi_csi2_video_dev(video) \ > + container_of(video, struct sun6i_mipi_csi2_dev, video) > + > +#endif /* __SUN6I_MIPI_CSI2_H__ */ -- Regards, Sakari Ailus From sakari.ailus at linux.intel.com Thu Nov 5 08:48:55 2020 From: sakari.ailus at linux.intel.com (Sakari Ailus) Date: Thu, 5 Nov 2020 10:48:55 +0200 Subject: [PATCH 11/14] dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation In-Reply-To: <20201023174546.504028-12-paul.kocialkowski@bootlin.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-12-paul.kocialkowski@bootlin.com> Message-ID: <20201105084855.GA26150@paasikivi.fi.intel.com> Hi Paul, On Fri, Oct 23, 2020 at 07:45:43PM +0200, Paul Kocialkowski wrote: > This introduces YAML bindings documentation for the A83T MIPI CSI-2 > controller. > > Signed-off-by: Paul Kocialkowski > --- > .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 ++++++++++++++++++ > 1 file changed, 158 insertions(+) > create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > > diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > new file mode 100644 > index 000000000000..2384ae4e7be0 > --- /dev/null > +++ b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > @@ -0,0 +1,158 @@ > +# SPDX-License-Identifier: GPL-2.0 > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-mipi-csi2.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Allwinner A83T MIPI CSI-2 Device Tree Bindings > + > +maintainers: > + - Paul Kocialkowski > + > +properties: > + compatible: > + const: allwinner,sun8i-a83t-mipi-csi2 > + > + reg: > + maxItems: 1 > + > + interrupts: > + maxItems: 1 > + > + clocks: > + items: > + - description: Bus Clock > + - description: Module Clock > + - description: MIPI-specific Clock > + - description: Misc CSI Clock > + > + clock-names: > + items: > + - const: bus > + - const: mod > + - const: mipi > + - const: misc > + > + resets: > + maxItems: 1 > + > + # See ./video-interfaces.txt for details > + ports: > + type: object > + > + properties: > + port at 0: > + type: object > + description: Input port, connect to a MIPI CSI-2 sensor > + > + properties: > + reg: > + const: 0 > + > + endpoint: > + type: object > + > + properties: > + remote-endpoint: true > + > + bus-type: > + const: 4 Again, if this is D-PHY only, you can remove this. > + > + clock-lanes: > + maxItems: 1 > + > + data-lanes: > + minItems: 1 > + maxItems: 4 Does the device support lane reordering? If not, you can remove clock-lanes. > + > + required: > + - bus-type > + - data-lanes > + - remote-endpoint > + > + additionalProperties: false > + > + required: > + - endpoint > + > + additionalProperties: false > + > + port at 1: > + type: object > + description: Output port, connect to a CSI controller > + > + properties: > + reg: > + const: 1 > + > + endpoint: > + type: object > + > + properties: > + remote-endpoint: true > + > + bus-type: > + const: 4 Is it a MIPI CSI-2 D-PHY -> MIPI CSI-2 D-PHY device? I call that "cable". :-) > + > + additionalProperties: false > + > + required: > + - endpoint > + > + additionalProperties: false > + > +required: > + - compatible > + - reg > + - interrupts > + - clocks > + - clock-names > + - resets > + > +additionalProperties: false > + > +examples: > + - | > + #include > + #include > + #include > + > + mipi_csi2: mipi-csi2 at 1cb1000 { > + compatible = "allwinner,sun8i-a83t-mipi-csi2"; > + reg = <0x01cb1000 0x1000>; > + interrupts = ; > + clocks = <&ccu CLK_BUS_CSI>, > + <&ccu CLK_CSI_SCLK>, > + <&ccu CLK_MIPI_CSI>, > + <&ccu CLK_CSI_MISC>; > + clock-names = "bus", "mod", "mipi", "misc"; > + resets = <&ccu RST_BUS_CSI>; > + > + ports { > + #address-cells = <1>; > + #size-cells = <0>; > + > + mipi_csi2_in: port at 0 { > + reg = <0>; > + > + mipi_csi2_in_ov8865: endpoint { > + bus-type = <4>; /* MIPI CSI-2 D-PHY */ > + clock-lanes = <0>; > + data-lanes = <1 2 3 4>; > + > + remote-endpoint = <&ov8865_out_mipi_csi2>; > + }; > + }; > + > + mipi_csi2_out: port at 1 { > + reg = <1>; > + > + mipi_csi2_out_csi: endpoint { > + bus-type = <4>; /* MIPI CSI-2 D-PHY */ > + remote-endpoint = <&csi_in_mipi_csi2>; > + }; > + }; > + }; > + }; > + > +... -- Regards, Sakari Ailus From jerome.pouiller at silabs.com Thu Nov 5 08:36:41 2020 From: jerome.pouiller at silabs.com (=?ISO-8859-1?Q?J=E9r=F4me?= Pouiller) Date: Thu, 05 Nov 2020 09:36:41 +0100 Subject: [PATCH v3 02/24] dt-bindings: introduce silabs,wfx.yaml In-Reply-To: <20201104191554.GA3972736@bogus> References: <20201104155207.128076-1-Jerome.Pouiller@silabs.com> <20201104155207.128076-3-Jerome.Pouiller@silabs.com> <20201104191554.GA3972736@bogus> Message-ID: <5127415.29KlJPOoH8@pc-42> On Wednesday 4 November 2020 20:15:54 CET Rob Herring wrote: > On Wed, 04 Nov 2020 16:51:45 +0100, Jerome Pouiller wrote: > > From: J?r?me Pouiller > > > > Signed-off-by: J?r?me Pouiller > > --- > > .../bindings/net/wireless/silabs,wfx.yaml | 131 ++++++++++++++++++ > > 1 file changed, 131 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml > > > > > My bot found errors running 'make dt_binding_check' on your patch: > > yamllint warnings/errors: > > dtschema/dtc warnings/errors: > /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml: 'additionalProperties' is a required property > /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml: ignoring, error in schema: > warning: no schema found in file: ./Documentation/devicetree/bindings/net/wireless/silabs,wfx.yaml > > > See https://patchwork.ozlabs.org/patch/1394182 > > The base for the patch is generally the last rc1. Any dependencies > should be noted. > > If you already ran 'make dt_binding_check' and didn't see the above > error(s), then make sure 'yamllint' is installed and dt-schema is up to > date: > > pip3 install dtschema --upgrade Weird, I don't have any error. Yet, yamllint is installed (1.24.2-1) and pip says that dts-schema is up-to-date (2020.8.2.dev2+gd63b653). I have also tried after rebased on v5.10-rc2, then on v5.10-rc1 without success. -- J?r?me Pouiller From bgolaszewski at baylibre.com Thu Nov 5 09:08:56 2020 From: bgolaszewski at baylibre.com (Bartosz Golaszewski) Date: Thu, 5 Nov 2020 10:08:56 +0100 Subject: [PATCH v3 03/11] gpio: raspberrypi-exp: Release firmware handle on unbind In-Reply-To: <20201104103938.1286-4-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-4-nsaenzjulienne@suse.de> Message-ID: On Wed, Nov 4, 2020 at 11:39 AM Nicolas Saenz Julienne wrote: > > Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware > interface when unbinding the device. > > Signed-off-by: Nicolas Saenz Julienne > > --- > > Changes since v2: > - Use devm_rpi_firmware_get(), instead of remove function > > drivers/gpio/gpio-raspberrypi-exp.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c > index bb100e0124e6..64a552ecc2ad 100644 > --- a/drivers/gpio/gpio-raspberrypi-exp.c > +++ b/drivers/gpio/gpio-raspberrypi-exp.c > @@ -208,7 +208,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) > return -ENOENT; > } > > - fw = rpi_firmware_get(fw_node); > + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); > of_node_put(fw_node); > if (!fw) > return -EPROBE_DEFER; > -- > 2.29.1 > Acked-by: Bartosz Golaszewski From bgolaszewski at baylibre.com Thu Nov 5 09:13:45 2020 From: bgolaszewski at baylibre.com (Bartosz Golaszewski) Date: Thu, 5 Nov 2020 10:13:45 +0100 Subject: [PATCH v3 01/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <20201104103938.1286-2-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-2-nsaenzjulienne@suse.de> Message-ID: On Wed, Nov 4, 2020 at 11:39 AM Nicolas Saenz Julienne wrote: > > When unbinding the firmware device we need to make sure it has no > consumers left. Otherwise we'd leave them with a firmware handle > pointing at freed memory. > > Keep a reference count of all consumers and introduce > devm_rpi_firmware_get() which will automatically decrease the reference > count upon unbinding consumer drivers. > > Suggested-by: Uwe Kleine-K?nig > Signed-off-by: Nicolas Saenz Julienne > > --- > > Changes since v2: > - Create devm_rpi_firmware_get() > > drivers/firmware/raspberrypi.c | 46 ++++++++++++++++++++++ > include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++ > 2 files changed, 54 insertions(+) > > diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c > index 2371d08bdd17..74bdb3bde9dc 100644 > --- a/drivers/firmware/raspberrypi.c > +++ b/drivers/firmware/raspberrypi.c > @@ -11,7 +11,9 @@ > #include > #include > #include > +#include > #include > +#include > #include > > #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) > @@ -27,6 +29,9 @@ struct rpi_firmware { > struct mbox_chan *chan; /* The property channel. */ > struct completion c; > u32 enabled; > + > + refcount_t consumers; > + wait_queue_head_t wait; > }; > > static DEFINE_MUTEX(transaction_lock); > @@ -247,6 +252,8 @@ static int rpi_firmware_probe(struct platform_device *pdev) > } > > init_completion(&fw->c); > + refcount_set(&fw->consumers, 1); > + init_waitqueue_head(&fw->wait); > > platform_set_drvdata(pdev, fw); > > @@ -275,11 +282,21 @@ static int rpi_firmware_remove(struct platform_device *pdev) > rpi_hwmon = NULL; > platform_device_unregister(rpi_clk); > rpi_clk = NULL; > + > + wait_event(fw->wait, refcount_dec_if_one(&fw->consumers)); > mbox_free_channel(fw->chan); > > return 0; > } > > +static void rpi_firmware_put(void *data) > +{ > + struct rpi_firmware *fw = data; > + > + refcount_dec(&fw->consumers); > + wake_up(&fw->wait); > +} > + > /** > * rpi_firmware_get - Get pointer to rpi_firmware structure. > * @firmware_node: Pointer to the firmware Device Tree node. > @@ -297,6 +314,35 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) > } > EXPORT_SYMBOL_GPL(rpi_firmware_get); > > +/** > + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. > + * @firmware_node: Pointer to the firmware Device Tree node. > + * > + * Returns NULL is the firmware device is not ready. > + */ > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node) > +{ > + struct platform_device *pdev = of_find_device_by_node(firmware_node); > + struct rpi_firmware *fw; > + > + if (!pdev) > + return NULL; > + > + fw = platform_get_drvdata(pdev); > + if (!fw) > + return NULL; > + > + if (!refcount_inc_not_zero(&fw->consumers)) > + return NULL; > + > + if (devm_add_action_or_reset(dev, rpi_firmware_put, fw)) > + return NULL; > + > + return fw; > +} > +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); Usually I'd expect the devres variant to simply call rpi_firmware_get() and then schedule a release callback which would call whatever function is the release counterpart for it currently. Devres actions are for drivers which want to schedule some more unusual tasks at driver detach. Any reason for designing it this way? Bartosz > + > static const struct of_device_id rpi_firmware_of_match[] = { > { .compatible = "raspberrypi,bcm2835-firmware", }, > {}, > diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h > index cc9cdbc66403..8fe64f53a394 100644 > --- a/include/soc/bcm2835/raspberrypi-firmware.h > +++ b/include/soc/bcm2835/raspberrypi-firmware.h > @@ -141,6 +141,8 @@ int rpi_firmware_property(struct rpi_firmware *fw, > int rpi_firmware_property_list(struct rpi_firmware *fw, > void *data, size_t tag_size); > struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node); > #else > static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, > void *data, size_t len) > @@ -158,6 +160,12 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware > { > return NULL; > } > + > +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node) > +{ > + return NULL; > +} > #endif > > #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ > -- > 2.29.1 > From nsaenzjulienne at suse.de Thu Nov 5 09:28:38 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 05 Nov 2020 10:28:38 +0100 Subject: [PATCH v3 01/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-2-nsaenzjulienne@suse.de> Message-ID: <47eaba0bc71c6e23bff87b8a01cebf0c6d12efd0.camel@suse.de> Hi Bartosz, thanks for the review. On Thu, 2020-11-05 at 10:13 +0100, Bartosz Golaszewski wrote: > > +/** > > + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. > > + * @firmware_node: Pointer to the firmware Device Tree node. > > + * > > + * Returns NULL is the firmware device is not ready. > > + */ > > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > > + struct device_node *firmware_node) > > +{ > > + struct platform_device *pdev = of_find_device_by_node(firmware_node); > > + struct rpi_firmware *fw; > > + > > + if (!pdev) > > + return NULL; > > + > > + fw = platform_get_drvdata(pdev); > > + if (!fw) > > + return NULL; > > + > > + if (!refcount_inc_not_zero(&fw->consumers)) > > + return NULL; > > + > > + if (devm_add_action_or_reset(dev, rpi_firmware_put, fw)) > > + return NULL; > > + > > + return fw; > > +} > > +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); > > Usually I'd expect the devres variant to simply call > rpi_firmware_get() and then schedule a release callback which would > call whatever function is the release counterpart for it currently. > Devres actions are for drivers which want to schedule some more > unusual tasks at driver detach. Any reason for designing it this way? Yes, see patch #8 where I get rid of rpi_firmware_get() altogether after converting all users to devres. Since there is no use for the vanilla version of the function anymore, I figured it'd be better to merge everything into devm_rpi_firmware_get(). That said it's not something I have strong feelings about. Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From bgolaszewski at baylibre.com Thu Nov 5 09:42:50 2020 From: bgolaszewski at baylibre.com (Bartosz Golaszewski) Date: Thu, 5 Nov 2020 10:42:50 +0100 Subject: [PATCH v3 01/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <47eaba0bc71c6e23bff87b8a01cebf0c6d12efd0.camel@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-2-nsaenzjulienne@suse.de> <47eaba0bc71c6e23bff87b8a01cebf0c6d12efd0.camel@suse.de> Message-ID: On Thu, Nov 5, 2020 at 10:28 AM Nicolas Saenz Julienne wrote: > > Hi Bartosz, thanks for the review. > > On Thu, 2020-11-05 at 10:13 +0100, Bartosz Golaszewski wrote: > > > +/** > > > + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. > > > + * @firmware_node: Pointer to the firmware Device Tree node. > > > + * > > > + * Returns NULL is the firmware device is not ready. > > > + */ > > > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > > > + struct device_node *firmware_node) > > > +{ > > > + struct platform_device *pdev = of_find_device_by_node(firmware_node); > > > + struct rpi_firmware *fw; > > > + > > > + if (!pdev) > > > + return NULL; > > > + > > > + fw = platform_get_drvdata(pdev); > > > + if (!fw) > > > + return NULL; > > > + > > > + if (!refcount_inc_not_zero(&fw->consumers)) > > > + return NULL; > > > + > > > + if (devm_add_action_or_reset(dev, rpi_firmware_put, fw)) > > > + return NULL; > > > + > > > + return fw; > > > +} > > > +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); > > > > Usually I'd expect the devres variant to simply call > > rpi_firmware_get() and then schedule a release callback which would > > call whatever function is the release counterpart for it currently. > > Devres actions are for drivers which want to schedule some more > > unusual tasks at driver detach. Any reason for designing it this way? > > Yes, see patch #8 where I get rid of rpi_firmware_get() altogether after > converting all users to devres. Since there is no use for the vanilla version > of the function anymore, I figured it'd be better to merge everything into > devm_rpi_firmware_get(). That said it's not something I have strong feelings > about. > I see. So the previous version didn't really have any reference counting and it leaked the reference returned by of_find_device_by_node(), got it. Could you just clarify for me the logic behind the wait_queue in rpi_firmware_remove()? If the firmware driver gets detached and remove() stops on the wait_queue - it will be stuck until the last user releases the firmware. I'm not sure this is correct. I'd prefer to see a kref with a release callback and remove would simply decrease the kref and return. Each user would do the same and then after the last user is detached the firmware would be destroyed. Don't we really have some centralized firmware subsystem that would handle this? Bartosz From ulf.hansson at linaro.org Thu Nov 5 09:45:23 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Thu, 5 Nov 2020 10:45:23 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201104234427.26477-1-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: + Viresh On Thu, 5 Nov 2020 at 00:44, Dmitry Osipenko wrote: > > Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces > power consumption and heating of the Tegra chips. Tegra SoC has multiple > hardware units which belong to a core power domain of the SoC and share > the core voltage. The voltage must be selected in accordance to a minimum > requirement of every core hardware unit. > > The minimum core voltage requirement depends on: > > 1. Clock enable state of a hardware unit. > 2. Clock frequency. > 3. Unit's internal idling/active state. > > This series is tested on Acer A500 (T20), AC100 (T20), Nexus 7 (T30) and > Ouya (T30) devices. I also added voltage scaling to the Ventana (T20) and > Cardhu (T30) boards which are tested by NVIDIA's CI farm. Tegra30 is now up > to 5C cooler on Nexus 7 and stays cool on Ouya (instead of becoming burning > hot) while system is idling. It should be possible to improve this further > by implementing a more advanced power management features for the kernel > drivers. > > The DVFS support is opt-in for all boards, meaning that older DTBs will > continue to work like they did it before this series. It should be possible > to easily add the core voltage scaling support for Tegra114+ SoCs based on > this grounding work later on, if anyone will want to implement it. > > WARNING(!) This series is made on top of the memory interconnect patches > which are currently under review [1]. The Tegra EMC driver > and devicetree-related patches need to be applied on top of > the ICC series. > > [1] https://patchwork.ozlabs.org/project/linux-tegra/list/?series=212196 > > Dmitry Osipenko (30): > dt-bindings: host1x: Document OPP and voltage regulator properties > dt-bindings: mmc: tegra: Document OPP and voltage regulator properties > dt-bindings: pwm: tegra: Document OPP and voltage regulator properties > media: dt: bindings: tegra-vde: Document OPP and voltage regulator > properties > dt-binding: usb: ci-hdrc-usb2: Document OPP and voltage regulator > properties > dt-bindings: usb: tegra-ehci: Document OPP and voltage regulator > properties > soc/tegra: Add sync state API > soc/tegra: regulators: Support Tegra SoC device sync state API > soc/tegra: regulators: Fix lockup when voltage-spread is out of range > regulator: Allow skipping disabled regulators in > regulator_check_consumers() > drm/tegra: dc: Support OPP and SoC core voltage scaling > drm/tegra: gr2d: Correct swapped device-tree compatibles > drm/tegra: gr2d: Support OPP and SoC core voltage scaling > drm/tegra: gr3d: Support OPP and SoC core voltage scaling > drm/tegra: hdmi: Support OPP and SoC core voltage scaling > gpu: host1x: Support OPP and SoC core voltage scaling > mmc: sdhci-tegra: Support OPP and core voltage scaling > pwm: tegra: Support OPP and core voltage scaling > media: staging: tegra-vde: Support OPP and SoC core voltage scaling > usb: chipidea: tegra: Support OPP and SoC core voltage scaling > usb: host: ehci-tegra: Support OPP and SoC core voltage scaling > memory: tegra20-emc: Support Tegra SoC device state syncing > memory: tegra30-emc: Support Tegra SoC device state syncing > ARM: tegra: Add OPP tables for Tegra20 peripheral devices > ARM: tegra: Add OPP tables for Tegra30 peripheral devices > ARM: tegra: ventana: Add voltage supplies to DVFS-capable devices > ARM: tegra: paz00: Add voltage supplies to DVFS-capable devices > ARM: tegra: acer-a500: Add voltage supplies to DVFS-capable devices > ARM: tegra: cardhu-a04: Add voltage supplies to DVFS-capable devices > ARM: tegra: nexus7: Add voltage supplies to DVFS-capable devices > > .../display/tegra/nvidia,tegra20-host1x.txt | 56 +++ > .../bindings/media/nvidia,tegra-vde.txt | 12 + > .../bindings/mmc/nvidia,tegra20-sdhci.txt | 12 + > .../bindings/pwm/nvidia,tegra20-pwm.txt | 13 + > .../devicetree/bindings/usb/ci-hdrc-usb2.txt | 4 + > .../bindings/usb/nvidia,tegra20-ehci.txt | 2 + > .../boot/dts/tegra20-acer-a500-picasso.dts | 30 +- > arch/arm/boot/dts/tegra20-paz00.dts | 40 +- > .../arm/boot/dts/tegra20-peripherals-opp.dtsi | 386 ++++++++++++++++ > arch/arm/boot/dts/tegra20-ventana.dts | 65 ++- > arch/arm/boot/dts/tegra20.dtsi | 14 + > .../tegra30-asus-nexus7-grouper-common.dtsi | 23 + > arch/arm/boot/dts/tegra30-cardhu-a04.dts | 44 ++ > .../arm/boot/dts/tegra30-peripherals-opp.dtsi | 415 ++++++++++++++++++ > arch/arm/boot/dts/tegra30.dtsi | 13 + > drivers/gpu/drm/tegra/Kconfig | 1 + > drivers/gpu/drm/tegra/dc.c | 138 +++++- > drivers/gpu/drm/tegra/dc.h | 5 + > drivers/gpu/drm/tegra/gr2d.c | 140 +++++- > drivers/gpu/drm/tegra/gr3d.c | 136 ++++++ > drivers/gpu/drm/tegra/hdmi.c | 63 ++- > drivers/gpu/host1x/Kconfig | 1 + > drivers/gpu/host1x/dev.c | 87 ++++ > drivers/memory/tegra/tegra20-emc.c | 8 +- > drivers/memory/tegra/tegra30-emc.c | 8 +- > drivers/mmc/host/Kconfig | 1 + > drivers/mmc/host/sdhci-tegra.c | 70 ++- > drivers/pwm/Kconfig | 1 + > drivers/pwm/pwm-tegra.c | 84 +++- > drivers/regulator/core.c | 12 +- > .../soc/samsung/exynos-regulator-coupler.c | 2 +- > drivers/soc/tegra/common.c | 152 ++++++- > drivers/soc/tegra/regulators-tegra20.c | 25 +- > drivers/soc/tegra/regulators-tegra30.c | 30 +- > drivers/staging/media/tegra-vde/Kconfig | 1 + > drivers/staging/media/tegra-vde/vde.c | 127 ++++++ > drivers/staging/media/tegra-vde/vde.h | 1 + > drivers/usb/chipidea/Kconfig | 1 + > drivers/usb/chipidea/ci_hdrc_tegra.c | 79 ++++ > drivers/usb/host/Kconfig | 1 + > drivers/usb/host/ehci-tegra.c | 79 ++++ > include/linux/regulator/coupler.h | 6 +- > include/soc/tegra/common.h | 22 + > 43 files changed, 2360 insertions(+), 50 deletions(-) > > -- > 2.27.0 > I need some more time to review this, but just a quick check found a few potential issues... The "core-supply", that you specify as a regulator for each controller's device node, is not the way we describe power domains. Instead, it seems like you should register a power-domain provider (with the help of genpd) and implement the ->set_performance_state() callback for it. Each device node should then be hooked up to this power-domain, rather than to a "core-supply". For DT bindings, please have a look at Documentation/devicetree/bindings/power/power-domain.yaml and Documentation/devicetree/bindings/power/power_domain.txt. In regards to the "sync state" problem (preventing to change performance states until all consumers have been attached), this can then be managed by the genpd provider driver instead. Kind regards Uffe From viresh.kumar at linaro.org Thu Nov 5 09:58:34 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Thu, 5 Nov 2020 15:28:34 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201104234427.26477-18-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> Message-ID: On Thu, Nov 5, 2020 at 5:15 AM Dmitry Osipenko wrote: > diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c > +static void sdhci_tegra_deinit_opp_table(void *data) > +{ > + struct device *dev = data; > + struct opp_table *opp_table; > + > + opp_table = dev_pm_opp_get_opp_table(dev); So you need to get an OPP table to put one :) You need to save the pointer returned by dev_pm_opp_set_regulators() instead. > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_regulators(opp_table); > + dev_pm_opp_put_opp_table(opp_table); > +} > + > +static int devm_sdhci_tegra_init_opp_table(struct device *dev) > +{ > + struct opp_table *opp_table; > + const char *rname = "core"; > + int err; > + > + /* voltage scaling is optional */ > + if (device_property_present(dev, "core-supply")) > + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); > + else > + opp_table = dev_pm_opp_get_opp_table(dev); Nice. I didn't think that someone will end up abusing this API and so made it available for all, but someone just did that. I will fix that in the OPP core. Any idea why you are doing what you are doing here ? > + > + if (IS_ERR(opp_table)) > + return dev_err_probe(dev, PTR_ERR(opp_table), > + "failed to prepare OPP table\n"); > + > + /* > + * OPP table presence is optional and we want the set_rate() of OPP > + * API to work similarly to clk_set_rate() if table is missing in a > + * device-tree. The add_table() errors out if OPP is missing in DT. > + */ > + if (device_property_present(dev, "operating-points-v2")) { > + err = dev_pm_opp_of_add_table(dev); > + if (err) { > + dev_err(dev, "failed to add OPP table: %d\n", err); > + goto put_table; > + } > + } > + > + err = devm_add_action(dev, sdhci_tegra_deinit_opp_table, dev); > + if (err) > + goto remove_table; > + > + return 0; > + > +remove_table: > + dev_pm_opp_of_remove_table(dev); > +put_table: > + dev_pm_opp_put_regulators(opp_table); > + > + return err; > +} > + > static int sdhci_tegra_probe(struct platform_device *pdev) > { > const struct of_device_id *match; > @@ -1621,6 +1681,10 @@ static int sdhci_tegra_probe(struct platform_device *pdev) > goto err_power_req; > } > > + rc = devm_sdhci_tegra_init_opp_table(&pdev->dev); > + if (rc) > + goto err_parse_dt; > + > /* > * Tegra210 has a separate SDMMC_LEGACY_TM clock used for host > * timeout clock and SW can choose TMCLK or SDCLK for hardware > -- > 2.27.0 > > _______________________________________________ > devel mailing list > devel at linuxdriverproject.org > http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel From viresh.kumar at linaro.org Thu Nov 5 10:06:03 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Thu, 5 Nov 2020 15:36:03 +0530 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <20201105100603.skrirm7uke4s2xyl@vireshk-i7> On 05-11-20, 10:45, Ulf Hansson wrote: > + Viresh Thanks Ulf. I found a bug in OPP core because you cc'd me here :) > On Thu, 5 Nov 2020 at 00:44, Dmitry Osipenko wrote: > I need some more time to review this, but just a quick check found a > few potential issues... > > The "core-supply", that you specify as a regulator for each > controller's device node, is not the way we describe power domains. Maybe I misunderstood your comment here, but there are two ways of scaling the voltage of a device depending on if it is a regulator (and can be modeled as one in the kernel) or a power domain. In case of Qcom earlier (when we added the performance-state stuff), the eventual hardware was out of kernel's control and we didn't wanted (allowed) to model it as a virtual regulator just to pass the votes to the RPM. And so we did what we did. But if the hardware (where the voltage is required to be changed) is indeed a regulator and is modeled as one, then what Dmitry has done looks okay. i.e. add a supply in the device's node and microvolt property in the DT entries. -- viresh From viresh.kumar at linaro.org Thu Nov 5 10:40:09 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Thu, 5 Nov 2020 16:10:09 +0530 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201105100603.skrirm7uke4s2xyl@vireshk-i7> Message-ID: <20201105104009.oo4dc6a2gdcwduhk@vireshk-i7> On 05-11-20, 11:34, Ulf Hansson wrote: > I am not objecting about scaling the voltage through a regulator, > that's fine to me. However, encoding a power domain as a regulator > (even if it may seem like a regulator) isn't. Well, unless Mark Brown > has changed his mind about this. > > In this case, it seems like the regulator supply belongs in the > description of the power domain provider. Okay, I wasn't sure if it is a power domain or a regulator here. Btw, how do we identify if it is a power domain or a regulator ? > > In case of Qcom earlier (when we added the performance-state stuff), > > the eventual hardware was out of kernel's control and we didn't wanted > > (allowed) to model it as a virtual regulator just to pass the votes to > > the RPM. And so we did what we did. > > > > But if the hardware (where the voltage is required to be changed) is > > indeed a regulator and is modeled as one, then what Dmitry has done > > looks okay. i.e. add a supply in the device's node and microvolt > > property in the DT entries. > > I guess I haven't paid enough attention how power domain regulators > are being described then. I was under the impression that the CPUfreq > case was a bit specific - and we had legacy bindings to stick with. > > Can you point me to some other existing examples of where power domain > regulators are specified as a regulator in each device's node? No, I thought it is a regulator here and not a power domain. -- viresh From dan.carpenter at oracle.com Thu Nov 5 10:41:02 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Thu, 5 Nov 2020 13:41:02 +0300 Subject: [PATCH -next] media: cedrus: fix reference leak in cedrus_start_streaming In-Reply-To: <2eb14a6d-4680-1527-0985-fd371e3ba2e8@xs4all.nl> References: <20201102142622.140001-1-zhangqilong3@huawei.com> <20201102141838.7oicqkeqy7vy3ki3@gilmour.lan> <2eb14a6d-4680-1527-0985-fd371e3ba2e8@xs4all.nl> Message-ID: <20201105104102.GA29398@kadam> On Wed, Nov 04, 2020 at 12:39:11PM +0100, Hans Verkuil wrote: > On 02/11/2020 15:18, Maxime Ripard wrote: > > On Mon, Nov 02, 2020 at 10:26:22PM +0800, Zhang Qilong wrote: > >> pm_runtime_get_sync will increment pm usage counter even it > >> failed. Forgetting to pm_runtime_put_noidle will result in > >> reference leak in cedrus_start_streaming. We should fix it. > >> > >> Fixes: d5aecd289babf ("media: cedrus: Implement runtime PM") > >> Signed-off-by: Zhang Qilong > > > > Shouldn't we fix pm_runtime_get_sync instead then? It seems that most of > > the callers get this wrong, and that's definitely non-obvious. > > It's been discussed before, but nobody stepped up to address this > issue. In the end I decided to just accept media patches that fix this > in the drivers rather than waiting for some mythical future core fix. > > Nor do I think that you can just 'fix' pm_runtime_get_sync, since > then you will get cases where pm_runtime_put is called once too > often. Someone could easily add a helper function. The only complication is thinking of the correct name. regards, dan carpenter From ulf.hansson at linaro.org Thu Nov 5 10:34:26 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Thu, 5 Nov 2020 11:34:26 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201105100603.skrirm7uke4s2xyl@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201105100603.skrirm7uke4s2xyl@vireshk-i7> Message-ID: On Thu, 5 Nov 2020 at 11:06, Viresh Kumar wrote: > > On 05-11-20, 10:45, Ulf Hansson wrote: > > + Viresh > > Thanks Ulf. I found a bug in OPP core because you cc'd me here :) Happy to help. :-) > > > On Thu, 5 Nov 2020 at 00:44, Dmitry Osipenko wrote: > > I need some more time to review this, but just a quick check found a > > few potential issues... > > > > The "core-supply", that you specify as a regulator for each > > controller's device node, is not the way we describe power domains. > > Maybe I misunderstood your comment here, but there are two ways of > scaling the voltage of a device depending on if it is a regulator (and > can be modeled as one in the kernel) or a power domain. I am not objecting about scaling the voltage through a regulator, that's fine to me. However, encoding a power domain as a regulator (even if it may seem like a regulator) isn't. Well, unless Mark Brown has changed his mind about this. In this case, it seems like the regulator supply belongs in the description of the power domain provider. > > In case of Qcom earlier (when we added the performance-state stuff), > the eventual hardware was out of kernel's control and we didn't wanted > (allowed) to model it as a virtual regulator just to pass the votes to > the RPM. And so we did what we did. > > But if the hardware (where the voltage is required to be changed) is > indeed a regulator and is modeled as one, then what Dmitry has done > looks okay. i.e. add a supply in the device's node and microvolt > property in the DT entries. I guess I haven't paid enough attention how power domain regulators are being described then. I was under the impression that the CPUfreq case was a bit specific - and we had legacy bindings to stick with. Can you point me to some other existing examples of where power domain regulators are specified as a regulator in each device's node? Kind regards Uffe From ulf.hansson at linaro.org Thu Nov 5 10:56:37 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Thu, 5 Nov 2020 11:56:37 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201105104009.oo4dc6a2gdcwduhk@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201105100603.skrirm7uke4s2xyl@vireshk-i7> <20201105104009.oo4dc6a2gdcwduhk@vireshk-i7> Message-ID: On Thu, 5 Nov 2020 at 11:40, Viresh Kumar wrote: > > On 05-11-20, 11:34, Ulf Hansson wrote: > > I am not objecting about scaling the voltage through a regulator, > > that's fine to me. However, encoding a power domain as a regulator > > (even if it may seem like a regulator) isn't. Well, unless Mark Brown > > has changed his mind about this. > > > > In this case, it seems like the regulator supply belongs in the > > description of the power domain provider. > > Okay, I wasn't sure if it is a power domain or a regulator here. Btw, > how do we identify if it is a power domain or a regulator ? Good question. It's not a crystal clear line in between them, I think. A power domain to me, means that some part of a silicon (a group of controllers or just a single piece, for example) needs some kind of resource (typically a power rail) to be enabled to be functional, to start with. If there are operating points involved, that's also a clear indication to me, that it's not a regular regulator. Maybe we should try to specify this more exactly in some documentation, somewhere. > > > > In case of Qcom earlier (when we added the performance-state stuff), > > > the eventual hardware was out of kernel's control and we didn't wanted > > > (allowed) to model it as a virtual regulator just to pass the votes to > > > the RPM. And so we did what we did. > > > > > > But if the hardware (where the voltage is required to be changed) is > > > indeed a regulator and is modeled as one, then what Dmitry has done > > > looks okay. i.e. add a supply in the device's node and microvolt > > > property in the DT entries. > > > > I guess I haven't paid enough attention how power domain regulators > > are being described then. I was under the impression that the CPUfreq > > case was a bit specific - and we had legacy bindings to stick with. > > > > Can you point me to some other existing examples of where power domain > > regulators are specified as a regulator in each device's node? > > No, I thought it is a regulator here and not a power domain. Okay, thanks! Kind regards Uffe From viresh.kumar at linaro.org Thu Nov 5 11:13:01 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Thu, 5 Nov 2020 16:43:01 +0530 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201105100603.skrirm7uke4s2xyl@vireshk-i7> <20201105104009.oo4dc6a2gdcwduhk@vireshk-i7> Message-ID: <20201105111301.2hxfx2tnmf2saakp@vireshk-i7> On 05-11-20, 11:56, Ulf Hansson wrote: > On Thu, 5 Nov 2020 at 11:40, Viresh Kumar wrote: > > Btw, how do we identify if it is a power domain or a regulator ? To be honest, I was a bit afraid and embarrassed to ask this question, and was hoping people to make fun of me in return :) > Good question. It's not a crystal clear line in between them, I think. And I was relieved after reading this :) > A power domain to me, means that some part of a silicon (a group of > controllers or just a single piece, for example) needs some kind of > resource (typically a power rail) to be enabled to be functional, to > start with. Isn't this what a part of regulator does as well ? i.e. enabling/disabling of the regulator or power to a group of controllers. Over that the regulator does voltage/current scaling as well, which normally the power domains don't do (though we did that in performance-state case). > If there are operating points involved, that's also a > clear indication to me, that it's not a regular regulator. Is there any example of that? I hope by OPP you meant both freq and voltage here. I am not sure if I know of a case where a power domain handles both of them. > Maybe we should try to specify this more exactly in some > documentation, somewhere. I think yes, it is very much required. And in absence of that I think, many (or most) of the platforms that also need to scale the voltage would have modeled their hardware as a regulator and not a PM domain. What I always thought was: - Module that can just enable/disable power to a block of SoC is a power domain. - Module that can enable/disable as well as scale voltage is a regulator. And so I thought that this patchset has done the right thing. This changed a bit with the qcom stuff where the IP to be configured was in control of RPM and not Linux and so we couldn't add it as a regulator. If it was controlled by Linux, it would have been a regulator in kernel for sure :) -- viresh From ulf.hansson at linaro.org Thu Nov 5 12:52:39 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Thu, 5 Nov 2020 13:52:39 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201105111301.2hxfx2tnmf2saakp@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201105100603.skrirm7uke4s2xyl@vireshk-i7> <20201105104009.oo4dc6a2gdcwduhk@vireshk-i7> <20201105111301.2hxfx2tnmf2saakp@vireshk-i7> Message-ID: On Thu, 5 Nov 2020 at 12:13, Viresh Kumar wrote: > > On 05-11-20, 11:56, Ulf Hansson wrote: > > On Thu, 5 Nov 2020 at 11:40, Viresh Kumar wrote: > > > Btw, how do we identify if it is a power domain or a regulator ? > > To be honest, I was a bit afraid and embarrassed to ask this question, > and was hoping people to make fun of me in return :) > > > Good question. It's not a crystal clear line in between them, I think. > > And I was relieved after reading this :) > > > A power domain to me, means that some part of a silicon (a group of > > controllers or just a single piece, for example) needs some kind of > > resource (typically a power rail) to be enabled to be functional, to > > start with. > > Isn't this what a part of regulator does as well ? i.e. > enabling/disabling of the regulator or power to a group of > controllers. It could, but it shouldn't. > > Over that the regulator does voltage/current scaling as well, which > normally the power domains don't do (though we did that in > performance-state case). > > > If there are operating points involved, that's also a > > clear indication to me, that it's not a regular regulator. > > Is there any example of that? I hope by OPP you meant both freq and > voltage here. I am not sure if I know of a case where a power domain > handles both of them. It may be both voltage and frequency - but in some cases only voltage. >From HW point of view, many ARM legacy platforms have power domains that work like this. As you know, the DVFS case has in many years not been solved in a generic way, but mostly via platform specific hacks. The worst ones are probably those hacking clock drivers (which myself also have contributed to). Have a look at clk_prcmu_opp_prepare(), for example, which is used by the UX500 platform. Another option has been to use the devfreq framework, but it has limitations in regards to this too. That said, I am hoping that people start moving towards the deploying/implementing DVFS through the power-domain approach, together with the OPPs. Maybe there are still some pieces missing from an infrastructure point of view, but that should become more evident as more starts using it. > > > Maybe we should try to specify this more exactly in some > > documentation, somewhere. > > I think yes, it is very much required. And in absence of that I think, > many (or most) of the platforms that also need to scale the voltage > would have modeled their hardware as a regulator and not a PM domain. > > What I always thought was: > > - Module that can just enable/disable power to a block of SoC is a > power domain. > > - Module that can enable/disable as well as scale voltage is a > regulator. > > And so I thought that this patchset has done the right thing. This > changed a bit with the qcom stuff where the IP to be configured was in > control of RPM and not Linux and so we couldn't add it as a regulator. > If it was controlled by Linux, it would have been a regulator in > kernel for sure :) In my view, DT bindings have consistently been pushed back during the year, if they have tried to model power domains as regulator supplies from consumer device nodes. Hence, people have tried other things, as I mentioned above. I definitely agree that we need to update some documentations, explaining things more exactly. Additionally, it seems like a talk at some conferences should make sense, as a way to spread the word. Kind regards Uffe From hverkuil at xs4all.nl Thu Nov 5 13:54:56 2020 From: hverkuil at xs4all.nl (Hans Verkuil) Date: Thu, 5 Nov 2020 14:54:56 +0100 Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: <20200912143052.30952-1-m.cerveny@computer.org> References: <20200912143052.30952-1-m.cerveny@computer.org> Message-ID: Hi Martin, On 12/09/2020 16:30, Martin Cerveny wrote: > First patch extends cedrus capability to all decoders > because V3s missing MPEG2 decoder. > > Next two patches add system control node (SRAM C1) and > next three patches add support for Cedrus VPU. > > Tested on "Lichee Zero" V3s platform with testing LCD patch > ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) > and V4L2 raw API testing utility > ( https://github.com/mcerveny/v4l2-request-test ): > - enabled LCD (DRM dual VI and sigle UI planes) > - added RGB panel > - enabled PWM > > There is low memory on V3s (64MB) and maximum must be available to CMA: > - CONFIG_CMA_SIZE_MBYTES=28 > - add swap to swapout other processes > - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) > > Only H.264 decoder working - MPEG and H.265 unsupported by V3s, > JPEG/MJPEG still unimplemented, encoder unimplemented When I tried to merged these patches I got merge conflicts. Possibly due to other 5.10 changes, but certainly because of conflicts with patches from Jernej: https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ I've merged Jerne's patches and posted a PR for that: https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ Can you rebase your patches on top of my branch that contains Jernej's patches? https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e Once my PR is merged into the media_tree master I can take your rebased patches. Regards, Hans > > best regards, > Martin > > Changes since v1: > - patch 0005 rename > - added testing description > > Martin Cerveny (6): > media: cedrus: Register all codecs as capability > dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s > compatibles > ARM: dts: sun8i: v3s: Add node for system control > media: cedrus: Add support for V3s > dt-bindings: media: cedrus: Add V3s compatible > ARM: dts: sun8i: v3s: Add video engine node > > .../allwinner,sun4i-a10-video-engine.yaml | 1 + > .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ > arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ > drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- > drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ > .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ > 6 files changed, 71 insertions(+), 1 deletion(-) > From digetx at gmail.com Thu Nov 5 13:57:26 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 16:57:26 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201105014502.GB17266@qmqm.qmqm.pl> References: <20201104234427.26477-1-digetx@gmail.com> <20201105014502.GB17266@qmqm.qmqm.pl> Message-ID: <60e6ea6b-3a02-30a1-f0c9-d33ef7906ed6@gmail.com> 05.11.2020 04:45, Micha? Miros?aw ?????: > On Thu, Nov 05, 2020 at 02:43:57AM +0300, Dmitry Osipenko wrote: >> Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs, which reduces >> power consumption and heating of the Tegra chips. Tegra SoC has multiple >> hardware units which belong to a core power domain of the SoC and share >> the core voltage. The voltage must be selected in accordance to a minimum >> requirement of every core hardware unit. > [...] > > Just looked briefly through the series - it looks like there is a lot of > code duplication in *_init_opp_table() functions. Could this be made > more generic / data-driven? Indeed, it should be possible to add a common helper. I had a quick thought about doing it too, but then decided to defer for the starter since there were some differences among the needs of the drivers. I'll take a closer look for the v2, thanks! From helen.koike at collabora.com Thu Nov 5 14:14:47 2020 From: helen.koike at collabora.com (Helen Koike) Date: Thu, 5 Nov 2020 11:14:47 -0300 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201104184538.f6qagsmjdoijbzmv@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <1a3a615c-a058-e282-2dbb-c99dfa98be68@collabora.com> <20201102092110.ro6a456lvbrktwoz@gilmour.lan> <20201104111710.GB287014@aptenodytes> <20201104184538.f6qagsmjdoijbzmv@gilmour.lan> Message-ID: <3b99b055-ff53-c873-19b2-fd2ccc86956d@collabora.com> On 11/4/20 3:45 PM, Maxime Ripard wrote: > On Wed, Nov 04, 2020 at 01:38:08PM -0300, Helen Koike wrote: >> >> >> On 11/4/20 8:17 AM, Paul Kocialkowski wrote: >>> Hi, >>> >>> On Mon 02 Nov 20, 10:21, Maxime Ripard wrote: >>>> On Fri, Oct 30, 2020 at 07:45:18PM -0300, Helen Koike wrote: >>>>> On 10/23/20 2:45 PM, Paul Kocialkowski wrote: >>>>>> The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller >>>>>> found on Allwinner SoCs such as the A31 and V3/V3s. >>>>>> >>>>>> It is a standalone block, connected to the CSI controller on one side >>>>>> and to the MIPI D-PHY block on the other. It has a dedicated address >>>>>> space, interrupt line and clock. >>>>>> >>>>>> Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI >>>>>> controller (CSI0) but newer SoCs (such as the V5) may allow switching >>>>>> MIPI CSI-2 controllers between CSI controllers. >>>>>> >>>>>> It is represented as a V4L2 subdev to the CSI controller and takes a >>>>>> MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and >>>>>> media controller API. >>>>> >>>>> Maybe this is a bad idea, but I was thinking: >>>>> This driver basically just turn on/off and catch some interrupts for errors, >>>>> and all the rest of v4l2 config you just forward to the next subdevice >>>>> on the pipeline. >>>>> >>>>> So instead of exposing it as a subdevice, I was wondering if modeling >>>>> this driver also through the phy subsystem wouldn't be cleaner, so >>>>> you won't need all the v4l2 subdevice/topology boilerplate code that >>>>> it seems you are not using (unless you have plans to add controls or >>>>> some specific configuration on this node later). >>>>> >>>>> But this would require changes on the sun6i-csi driver. >>>>> >>>>> What do you think? >>>> >>>> Eventually we'll need to filter the virtual channels / datatypes I >>>> guess, so it's definitely valuable to have it in v4l2 >> >> Which kind of datatypes? > > MIPI-CSI datatypes. Each packet on the MIPI-CSI bus is assigned a > virtual channel and data type so that you can multiplex multiple streams > (like a 3d camera would send for example, through the virtual channels) > and data types (like frames and metadata) and MIPI-CSI controllers > usually allow to filter them based on what you want. > >> I ask to know if this shouldn't be configured through the video node >> instead of subdevice. > > Not really, some setups have a mux that can split the multiple virtual > channels to multiple video nodes for example. > >> Regarding channels, we had a discussion to implement it through the video >> node (and not subdevice) [1]. But we discussed about blitters and multi-scalers, >> so now I'm wondering if we could use the same API for mipi-csi virtual channels >> in the video entity device, or if it doesn't apply and we need another API >> for that in a subdevice instead. >> >> [1] https://patchwork.linuxtv.org/project/linux-media/cover/20200717115435.2632623-1-helen.koike at collabora.com/ > > There's already an API to deal with MIPI-CSI virtual channels: > https://patchwork.kernel.org/project/linux-renesas-soc/cover/20190328200608.9463-1-jacopo+renesas at jmondi.org/ > > Maxime > Thanks for the explanation :) Helen From digetx at gmail.com Thu Nov 5 14:18:26 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 17:18:26 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> Message-ID: <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> 05.11.2020 12:58, Viresh Kumar ?????: >> +static void sdhci_tegra_deinit_opp_table(void *data) >> +{ >> + struct device *dev = data; >> + struct opp_table *opp_table; >> + >> + opp_table = dev_pm_opp_get_opp_table(dev); > So you need to get an OPP table to put one :) > You need to save the pointer returned by dev_pm_opp_set_regulators() instead. This is intentional because why do we need to save the pointer if we're not using it and we know that we could get this pointer using OPP API? This is exactly the same what I did for the CPUFreq driver [1] :) [1] https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/cpufreq/tegra20-cpufreq.c#L97 >> + dev_pm_opp_of_remove_table(dev); >> + dev_pm_opp_put_regulators(opp_table); >> + dev_pm_opp_put_opp_table(opp_table); >> +} >> + >> +static int devm_sdhci_tegra_init_opp_table(struct device *dev) >> +{ >> + struct opp_table *opp_table; >> + const char *rname = "core"; >> + int err; >> + >> + /* voltage scaling is optional */ >> + if (device_property_present(dev, "core-supply")) >> + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); >> + else > >> + opp_table = dev_pm_opp_get_opp_table(dev); > Nice. I didn't think that someone will end up abusing this API and so made it > available for all, but someone just did that. I will fix that in the OPP core. The dev_pm_opp_put_regulators() handles the case where regulator is missing by acting as dev_pm_opp_get_opp_table(), but the dev_pm_opp_set_regulators() doesn't do it. Hence I don't think this is an abuse, but the OPP API drawback. > Any idea why you are doing what you are doing here ? Two reasons: 1. Voltage regulator is optional, but dev_pm_opp_set_regulators() doesn't support optional regulators. 2. We need to balance the opp_table refcount in order to use OPP API without polluting code with if(have_regulator), hence the dev_pm_opp_get_opp_table() is needed for taking the opp_table reference to have the same refcount as in the case of the dev_pm_opp_set_regulators(). I guess we could make dev_pm_opp_set_regulators(dev, count) to accept regulators count=0 and then act as dev_pm_opp_get_opp_table(dev), will it be acceptable? From paul.kocialkowski at bootlin.com Thu Nov 5 14:52:24 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Thu, 5 Nov 2020 15:52:24 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201104185650.ii7dlekjtfar2xpp@gilmour.lan> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <20201026165407.rrq6ccsexcsub5bm@gilmour.lan> <20201104113458.GC287014@aptenodytes> <20201104185650.ii7dlekjtfar2xpp@gilmour.lan> Message-ID: <20201105145224.GA615923@aptenodytes> Hi, On Wed 04 Nov 20, 19:56, Maxime Ripard wrote: > On Wed, Nov 04, 2020 at 12:34:58PM +0100, Paul Kocialkowski wrote: > > > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, > > > > + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | > > > > + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); > > > > > > It's not really clear what the channel is here? The number of virtual > > > channels? Something else? > > > > That's somewhat described in the controller documentation. Channels refers to > > physical channels of the controller, which can be used to redirect data > > matching either a specific data type, a specific virtual channel, or both. > > There's a somewhat similar concept of channels in the CSI controller too. > > > > We're currently only using one... > > > > > > + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, > > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | > > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | > > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | > > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | > > > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); > > > > ... but it's safer to configure them all to virtual channel numbers so we don't > > end up with multiple channels matching virtual channel 0. > > > > I'll add a comment about that. > > Maybe we should have pads for all of them then, even if we don't support > changing anything? If that's something we can add later (I think it is), I would rather do this in a sub-sequent series to keep the current one lightweight and merged ASAP. It would also require some investigation to find out if the MIPI CSI-2 channel number i goes directly to the CSI controller channel number i or if some remapping can take place. What do you think? > > > > +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { > > > > + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, > > > > + .get_fmt = sun6i_mipi_csi2_get_fmt, > > > > + .set_fmt = sun6i_mipi_csi2_set_fmt, > > > > + .enum_frame_size = sun6i_mipi_csi2_enum_frame_size, > > > > + .enum_frame_interval = sun6i_mipi_csi2_enum_frame_interval, > > > > +}; > > > > + > > > > +/* Subdev */ > > > > + > > > > +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { > > > > + .core = &sun6i_mipi_csi2_subdev_core_ops, > > > > + .video = &sun6i_mipi_csi2_subdev_video_ops, > > > > + .pad = &sun6i_mipi_csi2_subdev_pad_ops, > > > > +}; > > > > + > > > > +/* Notifier */ > > > > + > > > > +static int sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, > > > > + struct v4l2_subdev *remote_subdev, > > > > + struct v4l2_async_subdev *remote_subdev_async) > > > > +{ > > > > + struct v4l2_subdev *subdev = notifier->sd; > > > > + struct sun6i_mipi_csi2_video *video = > > > > + sun6i_mipi_csi2_subdev_video(subdev); > > > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > > > + int source_pad; > > > > + int ret; > > > > + > > > > + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, > > > > + remote_subdev->fwnode, > > > > + MEDIA_PAD_FL_SOURCE); > > > > + if (source_pad < 0) > > > > + return source_pad; > > > > + > > > > + ret = media_create_pad_link(&remote_subdev->entity, source_pad, > > > > + &subdev->entity, 0, > > > > + MEDIA_LNK_FL_ENABLED | > > > > + MEDIA_LNK_FL_IMMUTABLE); > > > > + if (ret) { > > > > + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", > > > > + remote_subdev->entity.name, source_pad, > > > > + subdev->entity.name, 0); > > > > + return ret; > > > > + } > > > > + > > > > + video->remote_subdev = remote_subdev; > > > > + video->remote_pad_index = source_pad; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static const struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { > > > > + .bound = sun6i_mipi_csi2_notifier_bound, > > > > +}; > > > > + > > > > +/* Media Entity */ > > > > + > > > > +static int sun6i_mipi_csi2_link_validate(struct media_link *link) > > > > +{ > > > > + struct v4l2_subdev *subdev = > > > > + container_of(link->sink->entity, struct v4l2_subdev, entity); > > > > + struct sun6i_mipi_csi2_video *video = > > > > + sun6i_mipi_csi2_subdev_video(subdev); > > > > + struct v4l2_subdev *remote_subdev; > > > > + struct v4l2_subdev_format format = { 0 }; > > > > + int ret; > > > > + > > > > + if (!is_media_entity_v4l2_subdev(link->source->entity)) > > > > + return -EINVAL; > > > > + > > > > + remote_subdev = media_entity_to_v4l2_subdev(link->source->entity); > > > > + > > > > + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; > > > > + format.pad = link->source->index; > > > > + > > > > + ret = v4l2_subdev_call(remote_subdev, pad, get_fmt, NULL, &format); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + video->mbus_code = format.format.code; > > > > + > > > > + return 0; > > > > +} > > > > > > I'm not really sure what you're trying to validate here? > > > > The whole purpose is to retreive video->mbus_code from the subdev, like it's > > done in the sun6i-csi driver. Maybe there is a more appropriate op to do it? > > I'm not sure why you need to do that in the link_validate though? > > You just need to init the pad format, and then you'll have a > get_fmt/set_fmt for your pads. Okay I may have misunderstood how manual/automatic propagation is supposed to work then. The fact that this is done this way in the CSI driver maybe gave me a bad example to follow. I'll revisit this. > > > > + cdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, > > > > + &sun6i_mipi_csi2_regmap_config); > > > > + if (IS_ERR(cdev->regmap)) { > > > > + dev_err(&pdev->dev, "failed to init register map\n"); > > > > + return PTR_ERR(cdev->regmap); > > > > + } > > > > > > Yeah, so that won't work. regmap expects to have access to those > > > registers when you enable that clock, but that won't happen since the > > > reset line can be disabled. You would be better off using runtime_pm > > > here. > > > > I don't understand what you mean here or what the problem could be. > > Here we're just initializing regmap and while this is done before the > > registers are available for I/O, I don't see why it would cause any > > issue at this point. > > The regmap here is supposed to take care of the resources, except it > only does it for some of the resources here, which kind of breaks the > expectations. And it doesn't allow you to have the reset / clock > sequence properly done. I'm not following any of this. Could you break it down some more? In particular I don't see the relationship between initializing the regmap API (which does take IORESOURCE_MEM in) and reset / clocks. Just initializing the regmap API for I/O mem doesn't mean that the registers are ready for use, does it? We're not requesting any I/O operation from it at this point. > > The exact same thing is done in the CSI driver. > > That's not an argument though, is it? :) That's not the point, the point is rather that if this is wrong, we should fix it in the CSI driver as well. Paul -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Thu Nov 5 14:55:13 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Thu, 5 Nov 2020 15:55:13 +0100 Subject: [PATCH 08/14] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201105084556.GZ26150@paasikivi.fi.intel.com> References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201023174546.504028-9-paul.kocialkowski@bootlin.com> <20201105084556.GZ26150@paasikivi.fi.intel.com> Message-ID: <20201105145513.GB615923@aptenodytes> Hi Sakari and thanks for the review! On Thu 05 Nov 20, 10:45, Sakari Ailus wrote: > On Fri, Oct 23, 2020 at 07:45:40PM +0200, Paul Kocialkowski wrote: > > The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 controller > > found on Allwinner SoCs such as the A31 and V3/V3s. > > > > It is a standalone block, connected to the CSI controller on one side > > and to the MIPI D-PHY block on the other. It has a dedicated address > > space, interrupt line and clock. > > > > Currently, the MIPI CSI-2 controller is hard-tied to a specific CSI > > controller (CSI0) but newer SoCs (such as the V5) may allow switching > > MIPI CSI-2 controllers between CSI controllers. > > > > It is represented as a V4L2 subdev to the CSI controller and takes a > > MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and > > media controller API. > > > > Signed-off-by: Paul Kocialkowski > > --- > > drivers/media/platform/sunxi/Kconfig | 1 + > > drivers/media/platform/sunxi/Makefile | 1 + > > .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > > .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 ++++++++++++++++++ > > .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 ++++ > > 6 files changed, 768 insertions(+) > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > > > diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig > > index 7151cc249afa..9684e07454ad 100644 > > --- a/drivers/media/platform/sunxi/Kconfig > > +++ b/drivers/media/platform/sunxi/Kconfig > > @@ -2,3 +2,4 @@ > > > > source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" > > source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" > > +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" > > diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile > > index fc537c9f5ca9..887a7cae8fca 100644 > > --- a/drivers/media/platform/sunxi/Makefile > > +++ b/drivers/media/platform/sunxi/Makefile > > @@ -2,5 +2,6 @@ > > > > obj-y += sun4i-csi/ > > obj-y += sun6i-csi/ > > +obj-y += sun6i-mipi-csi2/ > > obj-y += sun8i-di/ > > obj-y += sun8i-rotate/ > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > new file mode 100644 > > index 000000000000..7033bda483b4 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > > @@ -0,0 +1,11 @@ > > +# SPDX-License-Identifier: GPL-2.0-only > > +config VIDEO_SUN6I_MIPI_CSI2 > > + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" > > + depends on VIDEO_V4L2 && COMMON_CLK > > + depends on ARCH_SUNXI || COMPILE_TEST > > + select MEDIA_CONTROLLER > > + select VIDEO_V4L2_SUBDEV_API > > + select REGMAP_MMIO > > + select V4L2_FWNODE > > + help > > + Support for the Allwinner A31 MIPI CSI-2 Controller. > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > new file mode 100644 > > index 000000000000..14e4e03818b5 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > > @@ -0,0 +1,4 @@ > > +# SPDX-License-Identifier: GPL-2.0-only > > +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o > > + > > +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > new file mode 100644 > > index 000000000000..ce89c35f5b86 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > > @@ -0,0 +1,635 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright 2020 Bootlin > > + * Author: Paul Kocialkowski > > + */ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include "sun6i_mipi_csi2.h" > > + > > +#define MODULE_NAME "sun6i-mipi-csi2" > > + > > +/* Core */ > > + > > +static irqreturn_t sun6i_mipi_csi2_isr(int irq, void *dev_id) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev = (struct sun6i_mipi_csi2_dev *)dev_id; > > Unnecessary casting from void *. > > > + struct regmap *regmap = cdev->regmap; > > + u32 pending; > > + > > + WARN_ONCE(1, MODULE_NAME > > + ": Unsolicited interrupt, an error likely occurred!\n"); > > + > > + regmap_read(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, &pending); > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CH_INT_PD_REG, pending); > > + > > + /* > > + * The interrupt can be used to catch transmission errors. > > + * However, we currently lack plumbing for reporting that to the > > + * A31 CSI controller driver. > > + */ > > + > > + return IRQ_HANDLED; > > +} > > + > > +static int sun6i_mipi_csi2_s_power(struct v4l2_subdev *subdev, int on) > > Please use runtime PM instead. > > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + int ret; > > + > > + if (!on) { > > + clk_disable_unprepare(cdev->clk_mod); > > + reset_control_assert(cdev->reset); > > + > > + return 0; > > + } > > + > > + ret = clk_prepare_enable(cdev->clk_mod); > > + if (ret) { > > + dev_err(cdev->dev, "failed to enable module clock\n"); > > + return ret; > > + } > > + > > + ret = reset_control_deassert(cdev->reset); > > + if (ret) { > > + dev_err(cdev->dev, "failed to deassert reset\n"); > > + goto error_clk; > > + } > > + > > + return 0; > > + > > +error_clk: > > + clk_disable_unprepare(cdev->clk_mod); > > + > > + return ret; > > +} > > + > > +static const struct v4l2_subdev_core_ops sun6i_mipi_csi2_subdev_core_ops = { > > + .s_power = sun6i_mipi_csi2_s_power, > > +}; > > + > > +/* Video */ > > + > > +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + struct v4l2_subdev *remote_subdev = video->remote_subdev; > > + struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = > > + &video->endpoint.bus.mipi_csi2; > > + union phy_configure_opts dphy_opts = { 0 }; > > + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; > > + struct regmap *regmap = cdev->regmap; > > + struct v4l2_ctrl *ctrl; > > + unsigned int lanes_count; > > + unsigned int bpp; > > + unsigned long pixel_rate; > > + u8 data_type = 0; > > + u32 version = 0; > > + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ > > + int ret = 0; > > + > > + if (!remote_subdev) > > + return -ENODEV; > > + > > + if (!on) { > > + v4l2_subdev_call(remote_subdev, video, s_stream, 0); > > + > > +disable: > > I think this label would be nicer at the end of the function (so you'd have > a goto here). It looks like everyone hates the backwards goto, even when there are no bad side-effects attached to it. I'll go for moving it to the end then :) > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_EN, 0); > > + > > + phy_power_off(cdev->dphy); > > + > > + return ret; > > + } > > + > > + switch (video->mbus_code) { > > + case MEDIA_BUS_FMT_SBGGR8_1X8: > > + case MEDIA_BUS_FMT_SGBRG8_1X8: > > + case MEDIA_BUS_FMT_SGRBG8_1X8: > > + case MEDIA_BUS_FMT_SRGGB8_1X8: > > + data_type = MIPI_CSI2_DATA_TYPE_RAW8; > > + bpp = 8; > > + break; > > + case MEDIA_BUS_FMT_SBGGR10_1X10: > > + case MEDIA_BUS_FMT_SGBRG10_1X10: > > + case MEDIA_BUS_FMT_SGRBG10_1X10: > > + case MEDIA_BUS_FMT_SRGGB10_1X10: > > + data_type = MIPI_CSI2_DATA_TYPE_RAW10; > > + bpp = 10; > > + break; > > + default: > > + return -EINVAL; > > + } > > + > > + /* Sensor pixel rate */ > > + > > + ctrl = v4l2_ctrl_find(remote_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); > > + if (!ctrl) { > > + dev_err(cdev->dev, > > + "%s: no MIPI CSI-2 pixel rate from the sensor\n", > > + __func__); > > + return -ENODEV; > > + } > > + > > + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); > > + if (!pixel_rate) { > > + dev_err(cdev->dev, > > + "%s: zero MIPI CSI-2 pixel rate from the sensor\n", > > + __func__); > > + return -ENODEV; > > + } > > + > > + /* D-PHY configuration */ > > + > > + lanes_count = bus_mipi_csi2->num_data_lanes; > > + phy_mipi_dphy_get_default_config(pixel_rate, bpp, lanes_count, > > + dphy_cfg); > > + > > + > > + /* > > + * Note that our hardware is using DDR, which is not taken in account by > > + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from > > + * the pixel rate, lanes count and bpp. > > + * > > + * The resulting clock rate is basically the symbol rate over the whole > > + * link. The actual clock rate is calculated with division by two since > > + * DDR samples both on rising and falling edges. > > + */ > > + > > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 config:\n"); > > + dev_dbg(cdev->dev, "%ld pixels/s, %u bits/pixel, %lu Hz clock\n", > > + pixel_rate, bpp, dphy_cfg->hs_clk_rate / 2); > > + > > + ret = 0; > > + ret |= phy_reset(cdev->dphy); > > + ret |= phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, > > + PHY_MIPI_DPHY_SUBMODE_RX); > > + ret |= phy_configure(cdev->dphy, &dphy_opts); > > Huh. Please don't do bitwise or operations on error codes. > > > + > > + if (ret) { > > + dev_err(cdev->dev, "failed to setup MIPI D-PHY\n"); > > + return ret; > > + } > > + > > + ret = phy_power_on(cdev->dphy); > > + if (ret) { > > + dev_err(cdev->dev, "failed to power on MIPI D-PHY\n"); > > + return ret; > > + } > > + > > + /* MIPI CSI-2 controller setup */ > > + > > + /* > > + * The enable flow in the Allwinner BSP is a bit different: the enable > > + * and reset bits are set together before starting the CSI controller. > > + * > > + * In mainline we enable the CSI controller first (due to subdev logic). > > + * One reliable way to make this work is to deassert reset, configure > > + * registers and enable the controller when everything's ready. > > + * > > + * However, reading the version appears necessary for it to work > > + * reliably. Replacing it with a delay doesn't do the trick. > > + */ > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_RESET_N | > > + SUN6I_MIPI_CSI2_CTL_VERSION_EN | > > + SUN6I_MIPI_CSI2_CTL_UNPK_EN); > > + > > + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); > > + > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); > > + > > + dev_dbg(cdev->dev, "A31 MIPI CSI-2 version: %04x\n", version); > > + > > + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, > > + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | > > + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); > > + > > + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | > > + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); > > + > > + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, > > + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); > > + > > + ret = v4l2_subdev_call(remote_subdev, video, s_stream, 1); > > + if (ret) > > + goto disable; > > + > > + return 0; > > +} > > + > > +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_subdev_video_ops = { > > + .s_stream = sun6i_mipi_csi2_s_stream, > > +}; > > + > > +/* Pad */ > > + > > +static int sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_mbus_code_enum *code_enum) > > You can easily get under 80 characters per line if you wrap after the > function's return type. > > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + code_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_mbus_code, > > + config, code_enum); > > +} > > + > > +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_format *format) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + format->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, get_fmt, config, > > + format); > > The entity this driver controls is independent of the upstream device in > its configuratione, you should not try to propagate the configuration > upstream in the pipeline. > > The same applies to other similar functions in the driver. > > > +} > > + > > +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_format *format) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + format->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, set_fmt, config, > > + format); > > +} > > + > > +static int sun6i_mipi_csi2_enum_frame_size(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_frame_size_enum *size_enum) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + size_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_size, > > + config, size_enum); > > +} > > + > > +static int sun6i_mipi_csi2_enum_frame_interval(struct v4l2_subdev *subdev, > > + struct v4l2_subdev_pad_config *config, > > + struct v4l2_subdev_frame_interval_enum *interval_enum) > > +{ > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + > > + if (!video->remote_subdev) > > + return -ENODEV; > > + > > + /* Forward to the sensor. */ > > + interval_enum->pad = video->remote_pad_index; > > + > > + return v4l2_subdev_call(video->remote_subdev, pad, enum_frame_interval, > > + config, interval_enum); > > +} > > + > > +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { > > + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, > > + .get_fmt = sun6i_mipi_csi2_get_fmt, > > + .set_fmt = sun6i_mipi_csi2_set_fmt, > > + .enum_frame_size = sun6i_mipi_csi2_enum_frame_size, > > + .enum_frame_interval = sun6i_mipi_csi2_enum_frame_interval, > > +}; > > + > > +/* Subdev */ > > + > > +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { > > + .core = &sun6i_mipi_csi2_subdev_core_ops, > > + .video = &sun6i_mipi_csi2_subdev_video_ops, > > + .pad = &sun6i_mipi_csi2_subdev_pad_ops, > > +}; > > + > > +/* Notifier */ > > + > > +static int sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, > > + struct v4l2_subdev *remote_subdev, > > + struct v4l2_async_subdev *remote_subdev_async) > > +{ > > + struct v4l2_subdev *subdev = notifier->sd; > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); > > + int source_pad; > > + int ret; > > + > > + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, > > + remote_subdev->fwnode, > > + MEDIA_PAD_FL_SOURCE); > > + if (source_pad < 0) > > + return source_pad; > > + > > + ret = media_create_pad_link(&remote_subdev->entity, source_pad, > > + &subdev->entity, 0, > > + MEDIA_LNK_FL_ENABLED | > > + MEDIA_LNK_FL_IMMUTABLE); > > + if (ret) { > > + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", > > + remote_subdev->entity.name, source_pad, > > + subdev->entity.name, 0); > > + return ret; > > + } > > + > > + video->remote_subdev = remote_subdev; > > + video->remote_pad_index = source_pad; > > + > > + return 0; > > +} > > + > > +static const struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { > > + .bound = sun6i_mipi_csi2_notifier_bound, > > +}; > > + > > +/* Media Entity */ > > + > > +static int sun6i_mipi_csi2_link_validate(struct media_link *link) > > +{ > > + struct v4l2_subdev *subdev = > > + container_of(link->sink->entity, struct v4l2_subdev, entity); > > + struct sun6i_mipi_csi2_video *video = > > + sun6i_mipi_csi2_subdev_video(subdev); > > + struct v4l2_subdev *remote_subdev; > > + struct v4l2_subdev_format format = { 0 }; > > + int ret; > > + > > + if (!is_media_entity_v4l2_subdev(link->source->entity)) > > + return -EINVAL; > > + > > + remote_subdev = media_entity_to_v4l2_subdev(link->source->entity); > > + > > + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; > > + format.pad = link->source->index; > > + > > + ret = v4l2_subdev_call(remote_subdev, pad, get_fmt, NULL, &format); > > + if (ret) > > + return ret; > > + > > + video->mbus_code = format.format.code; > > + > > + return 0; > > +} > > + > > +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { > > + .link_validate = sun6i_mipi_csi2_link_validate, > > +}; > > + > > +/* Base Driver */ > > + > > +static int sun6i_mipi_csi2_v4l2_setup(struct sun6i_mipi_csi2_dev *cdev) > > +{ > > + struct sun6i_mipi_csi2_video *video = &cdev->video; > > + struct v4l2_subdev *subdev = &video->subdev; > > + struct v4l2_async_notifier *notifier = &video->notifier; > > + struct fwnode_handle *handle; > > + struct v4l2_fwnode_endpoint *endpoint; > > + int ret; > > + > > + /* Subdev */ > > + > > + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); > > + subdev->dev = cdev->dev; > > + strscpy(subdev->name, MODULE_NAME, sizeof(subdev->name)); > > + v4l2_set_subdevdata(subdev, cdev); > > + > > + /* Entity */ > > + > > + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; > > + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; > > Why is there no device node? This driver appears to be MC-enabled. Right, it looks like we need a subdev node here. I'll change that. Paul > > + > > + /* Pads */ > > + > > + video->pads[0].flags = MEDIA_PAD_FL_SINK; > > + video->pads[1].flags = MEDIA_PAD_FL_SOURCE; > > + > > + ret = media_entity_pads_init(&subdev->entity, 2, video->pads); > > + if (ret) > > + return ret; > > + > > + /* Endpoint */ > > + > > + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(cdev->dev), 0, 0, > > + FWNODE_GRAPH_ENDPOINT_NEXT); > > + if (!handle) > > + goto error_media_entity; > > + > > + endpoint = &video->endpoint; > > + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; > > + > > + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); > > + fwnode_handle_put(handle); > > + if (ret) > > + goto error_media_entity; > > + > > + /* Notifier */ > > + > > + v4l2_async_notifier_init(notifier); > > + > > + ret = v4l2_async_notifier_add_fwnode_remote_subdev(notifier, handle, > > + &video->subdev_async); > > + if (ret) > > + goto error_media_entity; > > + > > + video->notifier.ops = &sun6i_mipi_csi2_notifier_ops; > > + > > + ret = v4l2_async_subdev_notifier_register(subdev, notifier); > > + if (ret < 0) > > + goto error_notifier; > > + > > + /* Subdev */ > > + > > + ret = v4l2_async_register_subdev(subdev); > > + if (ret < 0) > > + goto error_notifier_registered; > > + > > + return 0; > > + > > +error_notifier_registered: > > + v4l2_async_notifier_unregister(notifier); > > +error_notifier: > > + v4l2_async_notifier_cleanup(notifier); > > +error_media_entity: > > + media_entity_cleanup(&subdev->entity); > > + > > + return ret; > > +} > > + > > +static int sun6i_mipi_csi2_v4l2_teardown(struct sun6i_mipi_csi2_dev *cdev) > > +{ > > + struct sun6i_mipi_csi2_video *video = &cdev->video; > > + struct v4l2_subdev *subdev = &video->subdev; > > + struct v4l2_async_notifier *notifier = &video->notifier; > > + > > + v4l2_async_unregister_subdev(subdev); > > + v4l2_async_notifier_unregister(notifier); > > + v4l2_async_notifier_cleanup(notifier); > > + media_entity_cleanup(&subdev->entity); > > + v4l2_device_unregister_subdev(subdev); > > + > > + return 0; > > +} > > + > > +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { > > + .reg_bits = 32, > > + .reg_stride = 4, > > + .val_bits = 32, > > + .max_register = 0x400, > > +}; > > + > > +static int sun6i_mipi_csi2_resource_request(struct sun6i_mipi_csi2_dev *cdev, > > + struct platform_device *pdev) > > +{ > > + struct resource *res; > > + void __iomem *io_base; > > + int irq; > > + int ret; > > + > > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > > + io_base = devm_ioremap_resource(&pdev->dev, res); > > + if (IS_ERR(io_base)) > > + return PTR_ERR(io_base); > > + > > + cdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base, > > + &sun6i_mipi_csi2_regmap_config); > > + if (IS_ERR(cdev->regmap)) { > > + dev_err(&pdev->dev, "failed to init register map\n"); > > + return PTR_ERR(cdev->regmap); > > + } > > + > > + cdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); > > + if (IS_ERR(cdev->clk_mod)) { > > + dev_err(&pdev->dev, "failed to acquire csi clock\n"); > > + return PTR_ERR(cdev->clk_mod); > > + } > > + > > + cdev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); > > + if (IS_ERR(cdev->reset)) { > > + dev_err(&pdev->dev, "failed to get reset controller\n"); > > + return PTR_ERR(cdev->reset); > > + } > > + > > + irq = platform_get_irq(pdev, 0); > > + if (irq < 0) > > + return -ENXIO; > > + > > + ret = devm_request_irq(&pdev->dev, irq, sun6i_mipi_csi2_isr, 0, > > + MODULE_NAME, cdev); > > + if (ret) { > > + dev_err(&pdev->dev, "failed to request MIPI CSI-2 IRQ\n"); > > + return ret; > > + } > > + > > + cdev->dphy = devm_phy_get(&pdev->dev, "dphy"); > > + if (IS_ERR(cdev->dphy)) { > > + dev_err(&pdev->dev, "failed to get the MIPI D-PHY\n"); > > + return PTR_ERR(cdev->dphy); > > + } > > + > > + ret = phy_init(cdev->dphy); > > + if (ret) { > > + dev_err(&pdev->dev, "failed to initialize the MIPI D-PHY\n"); > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > +static int sun6i_mipi_csi2_probe(struct platform_device *pdev) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev; > > + int ret; > > + > > + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); > > + if (!cdev) > > + return -ENOMEM; > > + > > + cdev->dev = &pdev->dev; > > + > > + ret = sun6i_mipi_csi2_resource_request(cdev, pdev); > > + if (ret) > > + return ret; > > + > > + platform_set_drvdata(pdev, cdev); > > + > > + ret = sun6i_mipi_csi2_v4l2_setup(cdev); > > + if (ret) > > + return ret; > > + > > + return 0; > > +} > > + > > +static int sun6i_mipi_csi2_remove(struct platform_device *pdev) > > +{ > > + struct sun6i_mipi_csi2_dev *cdev = platform_get_drvdata(pdev); > > + > > + phy_exit(cdev->dphy); > > + > > + return sun6i_mipi_csi2_v4l2_teardown(cdev); > > +} > > + > > +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { > > + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, > > + { .compatible = "allwinner,sun8i-v3s-mipi-csi2", }, > > + {}, > > +}; > > +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); > > + > > +static struct platform_driver sun6i_mipi_csi2_platform_driver = { > > + .probe = sun6i_mipi_csi2_probe, > > + .remove = sun6i_mipi_csi2_remove, > > + .driver = { > > + .name = MODULE_NAME, > > + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), > > + }, > > +}; > > +module_platform_driver(sun6i_mipi_csi2_platform_driver); > > + > > +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); > > +MODULE_AUTHOR("Paul Kocialkowski "); > > +MODULE_LICENSE("GPL"); > > diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > new file mode 100644 > > index 000000000000..f3cce99bfd44 > > --- /dev/null > > +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > > @@ -0,0 +1,116 @@ > > +/* SPDX-License-Identifier: GPL-2.0+ */ > > +/* > > + * Copyright 2020 Bootlin > > + * Author: Paul Kocialkowski > > + */ > > + > > +#ifndef __SUN6I_MIPI_CSI2_H__ > > +#define __SUN6I_MIPI_CSI2_H__ > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define SUN6I_MIPI_CSI2_CTL_REG 0x0 > > +#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31) > > +#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30) > > +#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1) > > +#define SUN6I_MIPI_CSI2_CTL_EN BIT(0) > > +#define SUN6I_MIPI_CSI2_CFG_REG 0x4 > > +#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \ > > + GENMASK(9, 8)) > > +#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0)) > > +#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8 > > +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ > > + ((ch) * 8 + 6)) > > +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ > > + ((ch) * 8)) > > +#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc > > + > > +#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c > > + > > +#define SUN6I_MIPI_CSI2_CH_BASE 0x1000 > > +#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100 > > + > > +#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40 > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50 > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8) > > +#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0) > > + > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58 > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8) > > +#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0) > > + > > +#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60 > > +#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70 > > +#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74 > > +#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78 > > +#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c > > +#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80 > > + > > +#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \ > > + (SUN6I_MIPI_CSI2_CH_BASE + SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg)) > > + > > +enum mipi_csi2_data_type { > > + MIPI_CSI2_DATA_TYPE_RAW8 = 0x2a, > > + MIPI_CSI2_DATA_TYPE_RAW10 = 0x2b, > > + MIPI_CSI2_DATA_TYPE_RAW12 = 0x2c, > > +}; > > + > > +struct sun6i_mipi_csi2_video { > > + struct v4l2_fwnode_endpoint endpoint; > > + struct v4l2_subdev subdev; > > + struct media_pad pads[2]; > > + > > + struct v4l2_async_subdev subdev_async; > > + struct v4l2_async_notifier notifier; > > + > > + struct v4l2_subdev *remote_subdev; > > + u32 remote_pad_index; > > + u32 mbus_code; > > +}; > > + > > +struct sun6i_mipi_csi2_dev { > > + struct device *dev; > > + > > + struct regmap *regmap; > > + struct clk *clk_mod; > > + struct reset_control *reset; > > + struct phy *dphy; > > + > > + struct sun6i_mipi_csi2_video video; > > +}; > > + > > +#define sun6i_mipi_csi2_subdev_video(subdev) \ > > + container_of(subdev, struct sun6i_mipi_csi2_video, subdev) > > + > > +#define sun6i_mipi_csi2_video_dev(video) \ > > + container_of(video, struct sun6i_mipi_csi2_dev, video) > > + > > +#endif /* __SUN6I_MIPI_CSI2_H__ */ > > -- > Regards, > > Sakari Ailus -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From paul.kocialkowski at bootlin.com Thu Nov 5 14:58:21 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Thu, 5 Nov 2020 15:58:21 +0100 Subject: [PATCH 00/14] Allwinner MIPI CSI-2 support for A31/V3s/A83T In-Reply-To: References: <20201023174546.504028-1-paul.kocialkowski@bootlin.com> <20201104111137.GH285779@aptenodytes> Message-ID: <20201105145821.GC615923@aptenodytes> Hi, On Wed 04 Nov 20, 13:36, Helen Koike wrote: > Hi Paul, > > On 11/4/20 8:11 AM, Paul Kocialkowski wrote: > > Hi Helen, > > > > On Fri 30 Oct 20, 19:44, Helen Koike wrote: > >> Hi Paul, > >> > >> I have some comments through the series, I hope this helps. > > > > Thanks for your comments :) > > > >> On 10/23/20 2:45 PM, Paul Kocialkowski wrote: > >>> This series introduces support for MIPI CSI-2, with the A31 controller that is > >>> found on most SoCs (A31, V3s and probably V5) as well as the A83T-specific > >>> controller. While the former uses the same MIPI D-PHY that is already supported > >>> for DSI, the latter embeds its own D-PHY. > >>> > >>> In order to distinguish the use of the D-PHY between Rx mode (for MIPI CSI-2) > >>> and Tx mode (for MIPI DSI), a submode is introduced for D-PHY in the PHY API. > >>> This allows adding Rx support in the A31 D-PHY driver. > >>> > >>> A few changes and fixes are applied to the A31 CSI controller driver, in order > >>> to support the MIPI CSI-2 use-case. > >>> > >>> Follows is the V4L2 device topology representing the interactions between > >>> the MIPI CSI-2 sensor, the MIPI CSI-2 controller (which controls the D-PHY) > >>> and the CSI controller: > >>> - entity 1: sun6i-csi (1 pad, 1 link) > >>> type Node subtype V4L flags 0 > >>> device node name /dev/video0 > >>> pad0: Sink > >>> <- "sun6i-mipi-csi2":1 [ENABLED,IMMUTABLE] > >>> > >>> - entity 5: sun6i-mipi-csi2 (2 pads, 2 links) > >>> type V4L2 subdev subtype Unknown flags 0 > >>> pad0: Sink > >>> <- "ov5648 0-0036":0 [ENABLED,IMMUTABLE] > >>> pad1: Source > >>> -> "sun6i-csi":0 [ENABLED,IMMUTABLE] > >>> > >>> - entity 8: ov5648 0-0036 (1 pad, 1 link) > >>> type V4L2 subdev subtype Sensor flags 0 > >>> device node name /dev/v4l-subdev0 > >> > >> Question: I noticed is that sun6i-mipi-csi2 doesn't expose a node under /dev/, but the sensor > >> exposes it. Probably because it uses V4L2_SUBDEV_FL_HAS_DEVNODE and sun6i-csi() calls > >> v4l2_device_register_subdev_nodes(). > >> > >> I find this weird from a userspace pov, since usually we don't mix manual and auto propagation > >> of the configs, so I started wondering if sun6i-csi driver should be calling > >> v4l2_device_register_subdev_nodes() in the first place. > > > > I must admit that I didn't really pay attention to that, but since > > sun6i-mipi-csi2 is basically a bridge driver, it doesn't make sense to apply > > manual configuration to it. It is actually designed to forward most subdev ops > > to its own subdev so configuring it manually would actually result in > > configuring the sensor. > > Ack, then maybe sun6i-csi needs a patch removing the call to v4l2_device_register_subdev_nodes() Apparently Sakari suggested that we do need a subdev node for the MIPI CSI-2 bridge so I'll just do that. This implementation that fowards the ops to the sensor was apparently a mistake. Paul > > > > XXX > > > >> Also, sun6i-csi doesn't seem to be used by any board dts (it's declared on the dtsi, but I > >> didn't find any dts enabling it), so I wonder if it would be a bad thing if we update it. > >> > >>> pad0: Source > >>> [fmt:SBGGR8_1X8/640x480 at 1/30 field:none colorspace:raw xfer:none ycbcr:601 quantization:full-range] > >>> -> "sun6i-mipi-csi2":0 [ENABLED,IMMUTABLE] > >> > >> If I understand correctly, this is very similar to ipu3: > >> sensor->bus->dma_engine > >> > >> in the case of ipu3-cio2: > >> sensor->ipu3-csi2->ipu3-cio2 > >> > >> in this case: > >> ov5648->sun6i-mipi-csi2->sun6i-csi > > > > Yes this is the correct picture. > > > >> On thing that is confusing me is the name csi2 with csi (that makes me think of csi > >> version one, which is not the case), I would rename it to sun6i-video (or maybe > >> it is just me who gets confused). > > > > So the CSI name comes from the Allwinner litterature and implementation for that > > controller. Since it supports parallel input on its own, it does in fact support > > parallel CSI. The DMA engine part alone from that controller is also used for > > MIPI CSI-2, so in this case the name looses its relevance. > > > >> I know this driver is already upstream and not part of this series, but on the other hand it > >> doesn't seem to be used. > > > > Personally I don't find a rename to be necessary and while I agree that > > nothing would apparently prevent us from renaming it, I would prefer to keep > > the naming in line with Allwinner's litterature. > > Ok, I didn't know it was from Allwinner's litterature, I don't mind keeping the name. Great :) > >> On another note, I always wonder if we should expose the bus in the topology, I'm not > >> sure if it provides any useful API or information for userspace, and you could have > >> a cleaner code (maybe code could be under phy subsystem). But at the same time, it > >> seems this is a pattern on v4l2. > >> > >> I'd like to hear what others think on the above. > > > > My view on this is that we are dealing with two distinct controllers here, > > one that acts as a DMA engine and one that acts as a bridge. As a result, two > > chained subdevs looks like the most appropriate representation to me. > > > > Using the PHY subsystem would probably be abusing the framework since the > > MIPI CSI-2 controller is not a PHY (and we do have a D-PHY driver for the D-PHY > > part that uses the PHY API already). > > > > So tl;dr I don't agree that it would be cleaner. > > My point is, this is a "dummy" subdevice in userspace pov, > but if it is only used with auto-propagation of the configurations, then > it doesn't matter (since userspace won't interact with that node). > And in the kernel space you need to implement media boilerplate code. > So I was trying to think in another alternative, but tbh I don't mind > keeping it in the media topology. Undestood and thanks for sharing your thoughts either way, they are definitely welcome! Cheers, Paul > Regards, > Helen > > > > > Cheers, > > > > Paul > > > >>> Happy reviewing! > >>> > >>> Paul Kocialkowski (14): > >>> phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes > >>> phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI > >>> CSI-2 > >>> media: sun6i-csi: Support an optional dedicated memory pool > >>> media: sun6i-csi: Fix the image storage bpp for 10/12-bit Bayer > >>> formats > >>> media: sun6i-csi: Only configure the interface data width for parallel > >>> media: sun6i-csi: Support feeding from the MIPI CSI-2 controller > >>> dt-bindings: media: i2c: Add A31 MIPI CSI-2 bindings documentation > >>> media: sunxi: Add support for the A31 MIPI CSI-2 controller > >>> ARM: dts: sun8i: v3s: Add CSI0 camera interface node > >>> ARM: dts: sun8i: v3s: Add MIPI D-PHY and MIPI CSI-2 interface nodes > >>> dt-bindings: media: i2c: Add A83T MIPI CSI-2 bindings documentation > >>> media: sunxi: Add support for the A83T MIPI CSI-2 controller > >>> ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node > >>> media: sunxi: sun8i-a83t-mipi-csi2: Avoid using the (unsolicited) > >>> interrupt > >>> > >>> .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 168 +++++ > >>> .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 158 +++++ > >>> arch/arm/boot/dts/sun8i-a83t.dtsi | 26 + > >>> arch/arm/boot/dts/sun8i-v3s.dtsi | 62 ++ > >>> drivers/media/platform/sunxi/Kconfig | 2 + > >>> drivers/media/platform/sunxi/Makefile | 2 + > >>> .../platform/sunxi/sun6i-csi/sun6i_csi.c | 54 +- > >>> .../platform/sunxi/sun6i-csi/sun6i_csi.h | 20 +- > >>> .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 11 + > >>> .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + > >>> .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 635 +++++++++++++++++ > >>> .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 116 +++ > >>> .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + > >>> .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + > >>> .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ > >>> .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ > >>> .../sun8i_a83t_mipi_csi2.c | 660 ++++++++++++++++++ > >>> .../sun8i_a83t_mipi_csi2.h | 196 ++++++ > >>> drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 ++++- > >>> drivers/staging/media/rkisp1/rkisp1-isp.c | 3 +- > >>> include/linux/phy/phy-mipi-dphy.h | 13 + > >>> 21 files changed, 2408 insertions(+), 32 deletions(-) > >>> create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml > >>> create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml > >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig > >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile > >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c > >>> create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c > >>> create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h > >>> > > -- Paul Kocialkowski, Bootlin Embedded Linux and kernel engineering https://bootlin.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From digetx at gmail.com Thu Nov 5 15:22:09 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 18:22:09 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: 05.11.2020 12:45, Ulf Hansson ?????: ... > I need some more time to review this, but just a quick check found a > few potential issues... Thank you for starting the review! I'm pretty sure it will take a couple revisions until all the questions will be resolved :) > The "core-supply", that you specify as a regulator for each > controller's device node, is not the way we describe power domains. > Instead, it seems like you should register a power-domain provider > (with the help of genpd) and implement the ->set_performance_state() > callback for it. Each device node should then be hooked up to this > power-domain, rather than to a "core-supply". For DT bindings, please > have a look at Documentation/devicetree/bindings/power/power-domain.yaml > and Documentation/devicetree/bindings/power/power_domain.txt. > > In regards to the "sync state" problem (preventing to change > performance states until all consumers have been attached), this can > then be managed by the genpd provider driver instead. I'll need to take a closer look at GENPD, thank you for the suggestion. Sounds like a software GENPD driver which manages clocks and voltages could be a good idea, but it also could be an unnecessary over-engineering. Let's see.. From stern at rowland.harvard.edu Thu Nov 5 16:07:43 2020 From: stern at rowland.harvard.edu (Alan Stern) Date: Thu, 5 Nov 2020 11:07:43 -0500 Subject: [PATCH v1 21/30] usb: host: ehci-tegra: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-22-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-22-digetx@gmail.com> Message-ID: <20201105160743.GA1613614@rowland.harvard.edu> On Thu, Nov 05, 2020 at 02:44:18AM +0300, Dmitry Osipenko wrote: > Add initial OPP and SoC core voltage scaling support to the Tegra EHCI > driver. This is required for enabling system-wide DVFS on older Tegra > SoCs. > > Tested-by: Peter Geis > Tested-by: Nicolas Chauvet > Signed-off-by: Dmitry Osipenko > --- I'm no expert on OPP stuff, but some of what you have done here looks peculiar. > diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c > index 869d9c4de5fc..0976577f54b4 100644 > --- a/drivers/usb/host/ehci-tegra.c > +++ b/drivers/usb/host/ehci-tegra.c > @@ -17,6 +17,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -364,6 +365,79 @@ static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) > free_dma_aligned_buffer(urb); > } > > +static void tegra_ehci_deinit_opp_table(void *data) > +{ > + struct device *dev = data; > + struct opp_table *opp_table; > + > + opp_table = dev_pm_opp_get_opp_table(dev); > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_regulators(opp_table); > + dev_pm_opp_put_opp_table(opp_table); > +} > + > +static int devm_tegra_ehci_init_opp_table(struct device *dev) > +{ > + unsigned long rate = ULONG_MAX; > + struct opp_table *opp_table; > + const char *rname = "core"; > + struct dev_pm_opp *opp; > + int err; > + > + /* legacy device-trees don't have OPP table */ > + if (!device_property_present(dev, "operating-points-v2")) > + return 0; > + > + /* voltage scaling is optional */ > + if (device_property_present(dev, "core-supply")) > + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); > + else > + opp_table = dev_pm_opp_get_opp_table(dev); > + > + if (IS_ERR(opp_table)) > + return dev_err_probe(dev, PTR_ERR(opp_table), > + "failed to prepare OPP table\n"); > + > + err = dev_pm_opp_of_add_table(dev); > + if (err) { > + dev_err(dev, "failed to add OPP table: %d\n", err); > + goto put_table; > + } > + > + /* find suitable OPP for the maximum clock rate */ > + opp = dev_pm_opp_find_freq_floor(dev, &rate); > + err = PTR_ERR_OR_ZERO(opp); > + if (err) { > + dev_err(dev, "failed to get OPP: %d\n", err); > + goto remove_table; > + } > + > + dev_pm_opp_put(opp); > + > + /* > + * First dummy rate-set initializes voltage vote by setting voltage > + * in accordance to the clock rate. > + */ > + err = dev_pm_opp_set_rate(dev, rate); > + if (err) { > + dev_err(dev, "failed to initialize OPP clock: %d\n", err); > + goto remove_table; > + } > + > + err = devm_add_action(dev, tegra_ehci_deinit_opp_table, dev); > + if (err) > + goto remove_table; > + > + return 0; > + > +remove_table: > + dev_pm_opp_of_remove_table(dev); > +put_table: > + dev_pm_opp_put_regulators(opp_table); Do you really want to use the same error unwinding for opp_table values obtained from dev_pm_opp_set_regulators() as from dev_pm_opp_get_opp_table()? > + > + return err; > +} > + > static const struct tegra_ehci_soc_config tegra30_soc_config = { > .has_hostpc = true, > }; > @@ -431,6 +505,11 @@ static int tegra_ehci_probe(struct platform_device *pdev) > goto cleanup_hcd_create; > } > > + err = devm_tegra_ehci_init_opp_table(&pdev->dev); > + if (err) > + return dev_err_probe(&pdev->dev, err, > + "Failed to initialize OPP\n"); Why log a second error message? Just return err. Alan Stern From digetx at gmail.com Thu Nov 5 17:54:48 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 20:54:48 +0300 Subject: [PATCH v1 21/30] usb: host: ehci-tegra: Support OPP and SoC core voltage scaling In-Reply-To: <20201105160743.GA1613614@rowland.harvard.edu> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-22-digetx@gmail.com> <20201105160743.GA1613614@rowland.harvard.edu> Message-ID: 05.11.2020 19:07, Alan Stern ?????: > Do you really want to use the same error unwinding for opp_table values > obtained from dev_pm_opp_set_regulators() as from > dev_pm_opp_get_opp_table()? They both are pointing at the same opp_table, which is refcounted. The dev_pm_opp_set_regulators() is dev_pm_opp_get_opp_table() + it sets regulator for the table. https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/opp/core.c#L1756 From digetx at gmail.com Thu Nov 5 18:02:02 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 5 Nov 2020 21:02:02 +0300 Subject: [PATCH v1 21/30] usb: host: ehci-tegra: Support OPP and SoC core voltage scaling In-Reply-To: <20201105160743.GA1613614@rowland.harvard.edu> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-22-digetx@gmail.com> <20201105160743.GA1613614@rowland.harvard.edu> Message-ID: 05.11.2020 19:07, Alan Stern ?????: >> + err = devm_tegra_ehci_init_opp_table(&pdev->dev); >> + if (err) >> + return dev_err_probe(&pdev->dev, err, >> + "Failed to initialize OPP\n"); > Why log a second error message? Just return err. Indeed, thanks. From viresh.kumar at linaro.org Fri Nov 6 06:15:13 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Fri, 6 Nov 2020 11:45:13 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> Message-ID: <20201106061513.uyys7njcqcdlah67@vireshk-i7> On 05-11-20, 17:18, Dmitry Osipenko wrote: > 05.11.2020 12:58, Viresh Kumar ?????: > >> +static void sdhci_tegra_deinit_opp_table(void *data) > >> +{ > >> + struct device *dev = data; > >> + struct opp_table *opp_table; > >> + > >> + opp_table = dev_pm_opp_get_opp_table(dev); > > So you need to get an OPP table to put one :) > > You need to save the pointer returned by dev_pm_opp_set_regulators() instead. > > This is intentional because why do we need to save the pointer if we're > not using it and we know that we could get this pointer using OPP API? Because it is highly inefficient and it doesn't follow the rules set by the OPP core. Hypothetically speaking, the OPP core is free to allocate the OPP table structure as much as it wants, and if you don't use the value returned back to you earlier (think of it as a cookie assigned to your driver), then it will eventually lead to memory leak. > This is exactly the same what I did for the CPUFreq driver [1] :) I will strongly suggest you to save the pointer here and do the same in the cpufreq driver as well. > >> +static int devm_sdhci_tegra_init_opp_table(struct device *dev) > >> +{ > >> + struct opp_table *opp_table; > >> + const char *rname = "core"; > >> + int err; > >> + > >> + /* voltage scaling is optional */ > >> + if (device_property_present(dev, "core-supply")) > >> + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); > >> + else > > > >> + opp_table = dev_pm_opp_get_opp_table(dev); To make it further clear, this will end up allocating an OPP table for you, which it shouldn't have. > > Nice. I didn't think that someone will end up abusing this API and so made it > > available for all, but someone just did that. I will fix that in the OPP core. To be fair, I allowed the cpufreq-dt driver to abuse it too, which I am going to fix shortly. > The dev_pm_opp_put_regulators() handles the case where regulator is > missing by acting as dev_pm_opp_get_opp_table(), but the > dev_pm_opp_set_regulators() doesn't do it. Hence I don't think this is > an abuse, but the OPP API drawback. I am not sure what you meant here. Normally you are required to call dev_pm_opp_put_regulators() only if you have called dev_pm_opp_set_regulators() earlier. And the refcount stays in balance. > > Any idea why you are doing what you are doing here ? > > Two reasons: > > 1. Voltage regulator is optional, but dev_pm_opp_set_regulators() > doesn't support optional regulators. > > 2. We need to balance the opp_table refcount in order to use OPP API > without polluting code with if(have_regulator), hence the > dev_pm_opp_get_opp_table() is needed for taking the opp_table reference > to have the same refcount as in the case of the dev_pm_opp_set_regulators(). I am going to send a patchset shortly after which this call to dev_pm_opp_get_opp_table() will fail, if it is called before adding the OPP table. > I guess we could make dev_pm_opp_set_regulators(dev, count) to accept > regulators count=0 and then act as dev_pm_opp_get_opp_table(dev), will > it be acceptable? Setting regulators for count as 0 doesn't sound good to me. But, I understand that you don't want to have that if (have_regulator) check, and it is a fair request. What I will instead do is, allow all dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP table and fail silently. And so you won't be required to have this unwanted check. But you will be required to save the pointer returned back by dev_pm_opp_set_regulators(), which is the right thing to do anyways. -- viresh From siddhantgupta416 at gmail.com Fri Nov 6 08:22:26 2020 From: siddhantgupta416 at gmail.com (Siddhant Gupta) Date: Fri, 6 Nov 2020 13:52:26 +0530 Subject: [PATCH] staging: mt7621-dma: fix alignment warnings Message-ID: <20201106082226.GA22990@Sleakybeast> Fix the checkpatch warning of alignment should match open parenthesis for some dev_dbg() calls Signed-off-by: Siddhant Gupta --- drivers/staging/mt7621-dma/mtk-hsdma.c | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/staging/mt7621-dma/mtk-hsdma.c b/drivers/staging/mt7621-dma/mtk-hsdma.c index a9e1a1b14035..838fd05d33ee 100644 --- a/drivers/staging/mt7621-dma/mtk-hsdma.c +++ b/drivers/staging/mt7621-dma/mtk-hsdma.c @@ -208,24 +208,24 @@ static void mtk_hsdma_reset_chan(struct mtk_hsdam_engine *hsdma, static void hsdma_dump_reg(struct mtk_hsdam_engine *hsdma) { - dev_dbg(hsdma->ddev.dev, "tbase %08x, tcnt %08x, " - "tctx %08x, tdtx: %08x, rbase %08x, " - "rcnt %08x, rctx %08x, rdtx %08x\n", - mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), - mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), - mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX), - mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX), - mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE), - mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT), - mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), - mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); - - dev_dbg(hsdma->ddev.dev, "info %08x, glo %08x, delay %08x, intr_stat %08x, intr_mask %08x\n", - mtk_hsdma_read(hsdma, HSDMA_REG_INFO), - mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), - mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT), - mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS), - mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK)); + dev_dbg(hsdma->ddev.dev, + "tbase %08x, tcnt %08x, tctx %08x, tdtx: %08x, rbase %08x, rcnt %08x, rctx %08x, rdtx %08x\n", + mtk_hsdma_read(hsdma, HSDMA_REG_TX_BASE), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_CNT), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_CTX), + mtk_hsdma_read(hsdma, HSDMA_REG_TX_DTX), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_BASE), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_CNT), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_CRX), + mtk_hsdma_read(hsdma, HSDMA_REG_RX_DRX)); + + dev_dbg(hsdma->ddev.dev, + "info %08x, glo %08x, delay %08x, intr_stat %08x, intr_mask %08x\n", + mtk_hsdma_read(hsdma, HSDMA_REG_INFO), + mtk_hsdma_read(hsdma, HSDMA_REG_GLO_CFG), + mtk_hsdma_read(hsdma, HSDMA_REG_DELAY_INT), + mtk_hsdma_read(hsdma, HSDMA_REG_INT_STATUS), + mtk_hsdma_read(hsdma, HSDMA_REG_INT_MASK)); } static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, @@ -242,10 +242,10 @@ static void hsdma_dump_desc(struct mtk_hsdam_engine *hsdma, tx_desc = &chan->tx_ring[i]; rx_desc = &chan->rx_ring[i]; - dev_dbg(hsdma->ddev.dev, "%d tx addr0: %08x, flags %08x, " - "tx addr1: %08x, rx addr0 %08x, flags %08x\n", - i, tx_desc->addr0, tx_desc->flags, - tx_desc->addr1, rx_desc->addr0, rx_desc->flags); + dev_dbg(hsdma->ddev.dev, + "%d tx addr0: %08x, flags %08x, tx addr1: %08x, rx addr0 %08x, flags %08x\n", + i, tx_desc->addr0, tx_desc->flags, + tx_desc->addr1, rx_desc->addr0, rx_desc->flags); } } -- 2.25.1 From siddhantgupta416 at gmail.com Fri Nov 6 09:30:21 2020 From: siddhantgupta416 at gmail.com (Siddhant Gupta) Date: Fri, 6 Nov 2020 15:00:21 +0530 Subject: [PATCH] Staging: mt7621-pci: Fix alignment warnings Message-ID: <20201106093021.GA25237@Sleakybeast> Fix the alignment issue pointed out by checkpatch Signed-off-by: Siddhant Gupta --- drivers/staging/mt7621-pci/pci-mt7621.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index f961b353c22e..0e95fb33b4e9 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -278,8 +278,8 @@ static void setup_cm_memory_region(struct mt7621_pcie *pcie) write_gcr_reg1_base(mem_resource->start); write_gcr_reg1_mask(mask | CM_GCR_REGn_MASK_CMTGT_IOCU0); dev_info(dev, "PCI coherence region base: 0x%08llx, mask/settings: 0x%08llx\n", - (unsigned long long)read_gcr_reg1_base(), - (unsigned long long)read_gcr_reg1_mask()); + (unsigned long long)read_gcr_reg1_base(), + (unsigned long long)read_gcr_reg1_mask()); } } -- 2.25.1 From gregkh at linuxfoundation.org Fri Nov 6 09:43:44 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Fri, 6 Nov 2020 10:43:44 +0100 Subject: [PATCH v4 4/4] staging: mt7621-pci-phy: remove driver from staging In-Reply-To: <20201031122246.16497-5-sergio.paracuellos@gmail.com> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-5-sergio.paracuellos@gmail.com> Message-ID: <20201106094344.GA2641594@kroah.com> On Sat, Oct 31, 2020 at 01:22:46PM +0100, Sergio Paracuellos wrote: > Remove this driver from staging because it has been moved > into its properly place in the kernel. > > Signed-off-by: Sergio Paracuellos > --- > drivers/staging/Kconfig | 2 - > drivers/staging/Makefile | 1 - > drivers/staging/mt7621-pci-phy/Kconfig | 8 - > drivers/staging/mt7621-pci-phy/Makefile | 2 - > drivers/staging/mt7621-pci-phy/TODO | 4 - > .../mediatek,mt7621-pci-phy.yaml | 36 -- > .../staging/mt7621-pci-phy/pci-mt7621-phy.c | 373 ------------------ > 7 files changed, 426 deletions(-) > delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig > delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile > delete mode 100644 drivers/staging/mt7621-pci-phy/TODO > delete mode 100644 drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml > delete mode 100644 drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c Acked-by: Greg Kroah-Hartman From greg at kroah.com Fri Nov 6 10:01:49 2020 From: greg at kroah.com (Greg KH) Date: Fri, 6 Nov 2020 11:01:49 +0100 Subject: [PATCH] staging: fbtft: fb_watterott: fix usleep_range is preferred over udelay In-Reply-To: <20201101103244.GA284952@ubuntu> References: <20201101002010.278537-1-hassan@ninchat.com> <20201101063948.GB432418@kroah.com> <20201101103244.GA284952@ubuntu> Message-ID: <20201106100149.GA2705820@kroah.com> On Sun, Nov 01, 2020 at 12:32:44PM +0200, Hassan Shahbazi wrote: > On Sun, Nov 01, 2020 at 07:39:48AM +0100, Greg KH wrote: > > On Sun, Nov 01, 2020 at 02:20:10AM +0200, Hassan Shahbazi wrote: > > > Fix the checkpath.pl issue on fb_watterott.c. write_vmem and > > > write_vmem_8bit functions are within non-atomic context and can > > > safely use usleep_range. > > > see Documentation/timers/timers-howto.txt > > > > > > Signed-off-by: Hassan Shahbazi > > > --- > > > drivers/staging/fbtft/fb_watterott.c | 4 ++-- > > > 1 file changed, 2 insertions(+), 2 deletions(-) > > > > > > diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c > > > index 76b25df376b8..afcc86a17995 100644 > > > --- a/drivers/staging/fbtft/fb_watterott.c > > > +++ b/drivers/staging/fbtft/fb_watterott.c > > > @@ -84,7 +84,7 @@ static int write_vmem(struct fbtft_par *par, size_t offset, size_t len) > > > par->txbuf.buf, 10 + par->info->fix.line_length); > > > if (ret < 0) > > > return ret; > > > - udelay(300); > > > + usleep_range(300, 310); > > > } > > > > > > return 0; > > > @@ -124,7 +124,7 @@ static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len) > > > par->txbuf.buf, 10 + par->info->var.xres); > > > if (ret < 0) > > > return ret; > > > - udelay(700); > > > + usleep_range(700, 710); > > > > How do you know that these ranges are ok? Are you able to test these > > changes with real hardware? > > > > thanks, > > > > greg k-h > > No, I don't have the hardware to test with. I just used the current > value as the minimum and added an epsilon to it for the maximum > param. It's best not to guess about this, sorry, you should have the hardware to test this type of change. thanks, greg k-h From gregkh at linuxfoundation.org Fri Nov 6 10:03:43 2020 From: gregkh at linuxfoundation.org (Greg Kroah-Hartman) Date: Fri, 6 Nov 2020 11:03:43 +0100 Subject: [PATCH] staging: comedi: cb_pcidas: reinstate delay removed from trimpot setting In-Reply-To: <975358e2-6a08-211a-d232-3cd0ce628e8e@mev.co.uk> References: <20201029141833.126856-1-abbotti@mev.co.uk> <3d7cf15a-c389-ec2c-5e29-8838e8466790@mev.co.uk> <975358e2-6a08-211a-d232-3cd0ce628e8e@mev.co.uk> Message-ID: <20201106100343.GA2715339@kroah.com> On Wed, Nov 04, 2020 at 10:49:18AM +0000, Ian Abbott wrote: > On 02/11/2020 11:16, Ian Abbott wrote: > > On 02/11/2020 10:25, Ian Abbott wrote: > > > On 29/10/2020 14:18, Ian Abbott wrote: > > > > Commit eddd2a4c675c ("staging: comedi: cb_pcidas: refactor > > > > write_calibration_bitstream()") inadvertently removed one of the > > > > `udelay(1)` calls when writing to the calibration register in > > > > `cb_pcidas_calib_write()`.? Reinstate the delay.? It may seem strange > > > > that the delay is placed before the register write, but this function is > > > > called in a loop so the extra delay can make a difference. > > > > > > > > This _might_ solve reported issues reading analog inputs on a > > > > PCIe-DAS1602/16 card where the analog input values "were scaled in a > > > > strange way that didn't make sense".? On the same hardware running a > > > > system with a 3.13 kernel, and then a system with a 4.4 kernel, but with > > > > the same application software, the system with the 3.13 kernel was fine, > > > > but the one with the 4.4 kernel exhibited the problem.? Of the 90 > > > > changes to the driver between those kernel versions, this change looked > > > > like the most likely culprit. > > > > > > Actually, I've realized that this patch will have no effect on the > > > PCIe-DAS1602/16 card because it uses a different driver - > > > cb_pcimdas, not cb_pcidas. > > > > But that's also confusing because PCIe-DAS1602/16 was not supported > > until the 3.19 kernel!? I know the reported has both PCI-DAS1602/16 and > > PCIe-DAS1602/16 cards (supported by cb_pcidas and cb_pcimdas > > respectively), so there could have been some mix-up in the reporting. > > Mystery solved. The reporter had a mixture of PCIe-DAS1602/16 and > PCIM-DAS1602/16 cards (not PCI-DAS1602/16). Both of those are supported by > the "cb_pcimdas" driver (not "cb_pcidas"), although the PCIe card was not > supported until the 3.19 kernel (by commit 4e3d14af1286). Testing with the > 3.13 kernel was done with the PCIM card. > > The "strange scaling" was due to a change in the ranges reported for the > analog input subdevice in the 4.1 kernel (by commit c7549d770a27). Before > then, it just reported a single dummy range [0, 1000000] with no units > (converted to [0.0, 1.0] with no units by comedilib). Afterwards, it > reported four different voltage ranges (either unipolar or bipolar, > depending in a status bit tied to a physical switch). The reporter's > application code was using the reported range to scale the raw values to a > voltage (using comedilib functions), but because the reported range was > bogus, the application code was performing additional scaling (outside of > comedilib). The application code can be changed to check whether the device > is reporting a proper voltage range or the old, bogus range, and behave > accordingly. > > > > Greg, you might as well drop this patch if you haven't already > > > applied it, since it was only a hunch that it fixed a problem. > > That's still the case, although it won't do any harm if applied (apart from > the incorrect patch description). I'll leave it dropped :) thanks, greg k-h From gregkh at linuxfoundation.org Fri Nov 6 10:12:40 2020 From: gregkh at linuxfoundation.org (Greg Kroah-Hartman) Date: Fri, 6 Nov 2020 11:12:40 +0100 Subject: [PATCH] staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids In-Reply-To: References: Message-ID: <20201106101240.GA2770702@kroah.com> On Thu, Oct 29, 2020 at 09:52:16AM -0400, Brian O'Keefe wrote: > Add 024c:0627 to the list of SDIO device-ids, based on hardware found in > the wild. This hardware exists on at least some Acer SW1-011 tablets. > > Signed-off-by: Brian O'Keefe > Reviewed-by: Hans de Goede > --- > drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > index 5b1392deb0a7..7256d55fcc1b 100644 > --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > @@ -21,6 +21,7 @@ static const struct sdio_device_id sdio_ids[] = > { SDIO_DEVICE(0x024c, 0x0525), }, > { SDIO_DEVICE(0x024c, 0x0623), }, > { SDIO_DEVICE(0x024c, 0x0626), }, > + { SDIO_DEVICE(0x024c, 0x0627), }, > { SDIO_DEVICE(0x024c, 0xb723), }, > { /* end: all zeroes */ }, > }; > -- > 2.25.1 All of the tabs are gone in your email and it's only spaces, making this patch impossible to apply :( Can you fix up your email client and resend this and keep Hans's Reviewed-by on it? thanks, greg k-h From jen at uaic.utmachala.edu.ec Fri Nov 6 10:13:55 2020 From: jen at uaic.utmachala.edu.ec (=?UTF-8?Q?Jenny_Tseng=C2=A0=C2=A0?=) Date: Fri, 6 Nov 2020 10:13:55 +0000 Subject: Business Financing Message-ID: <581c0016b16047bf6940a007966b69c0@uaic.utmachala.edu.ec> >From the Desk of Jenny Tseng Hi, We are a Financial Strategic Firm specializing in Growth Financial Loans/Funding Investments. We specialize in investments in Private sectors in a broad range of areas, Within our Financial Investment Services are M&A development and Management,Financial & Operational management, Due diligence, Capital planning and Development including Real estate, Energy, Oil & Gas,Emerging markets, Digital content and Services. We wish to invest in any viable Projects with good ROI presented by your Management after review on your Business Model Presentation Plan. We intend to maintain a Silent/Financial Position on our Business with your Company.We look forward to your Swift response. Please respond to liweiart33 at gmail.com Regards, Jenny Tseng From digetx at gmail.com Fri Nov 6 13:17:13 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 6 Nov 2020 16:17:13 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201106061513.uyys7njcqcdlah67@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> Message-ID: 06.11.2020 09:15, Viresh Kumar ?????: > Setting regulators for count as 0 doesn't sound good to me. > > But, I understand that you don't want to have that if (have_regulator) > check, and it is a fair request. What I will instead do is, allow all > dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP > table and fail silently. And so you won't be required to have this > unwanted check. But you will be required to save the pointer returned > back by dev_pm_opp_set_regulators(), which is the right thing to do > anyways. Perhaps even a better variant could be to add a devm versions of the OPP API functions, then drivers won't need to care about storing the opp_table pointer if it's unused by drivers. From tiny.windzz at gmail.com Fri Nov 6 13:41:05 2020 From: tiny.windzz at gmail.com (Frank Lee) Date: Fri, 6 Nov 2020 21:41:05 +0800 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> Message-ID: On Fri, Nov 6, 2020 at 9:18 PM Dmitry Osipenko wrote: > > 06.11.2020 09:15, Viresh Kumar ?????: > > Setting regulators for count as 0 doesn't sound good to me. > > > > But, I understand that you don't want to have that if (have_regulator) > > check, and it is a fair request. What I will instead do is, allow all > > dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP > > table and fail silently. And so you won't be required to have this > > unwanted check. But you will be required to save the pointer returned > > back by dev_pm_opp_set_regulators(), which is the right thing to do > > anyways. > > Perhaps even a better variant could be to add a devm versions of the OPP > API functions, then drivers won't need to care about storing the > opp_table pointer if it's unused by drivers. I think so. The consumer may not be so concerned about the status of these OPP tables. If the driver needs to manage the release, it needs to add a pointer to their driver global structure. Maybe it's worth having these devm interfaces for opp. Yangtao From bokeefe at alum.wpi.edu Fri Nov 6 15:10:34 2020 From: bokeefe at alum.wpi.edu (Brian O'Keefe) Date: Fri, 6 Nov 2020 10:10:34 -0500 Subject: [PATCH] staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids Message-ID: Add 024c:0627 to the list of SDIO device-ids, based on hardware found in the wild. This hardware exists on at least some Acer SW1-011 tablets. Signed-off-by: Brian O'Keefe Reviewed-by: Hans de Goede --- drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c index 5b1392deb0a7..7256d55fcc1b 100644 --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c @@ -21,6 +21,7 @@ static const struct sdio_device_id sdio_ids[] = { SDIO_DEVICE(0x024c, 0x0525), }, { SDIO_DEVICE(0x024c, 0x0623), }, { SDIO_DEVICE(0x024c, 0x0626), }, + { SDIO_DEVICE(0x024c, 0x0627), }, { SDIO_DEVICE(0x024c, 0xb723), }, { /* end: all zeroes */ }, }; -- 2.25.1 From maxime at cerno.tech Fri Nov 6 15:14:08 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:08 +0100 Subject: [PATCH 4/7] media: sun4i: Remove the MBUS quirks In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-5-maxime@cerno.tech> Now that the MBUS quirks are applied by our global notifier, we can remove them from our CSI driver for the A10. Suggested-by: Christoph Hellwig Signed-off-by: Maxime Ripard --- .../platform/sunxi/sun4i-csi/sun4i_csi.c | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c index eb15c8c725ca..ec46cff80fdb 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c +++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c @@ -167,33 +167,6 @@ static int sun4i_csi_probe(struct platform_device *pdev) if (!csi->traits) return -EINVAL; - /* - * On Allwinner SoCs, some high memory bandwidth devices do DMA - * directly over the memory bus (called MBUS), instead of the - * system bus. The memory bus has a different addressing scheme - * without the DRAM starting offset. - * - * In some cases this can be described by an interconnect in - * the device tree. In other cases where the hardware is not - * fully understood and the interconnect is left out of the - * device tree, fall back to a default offset. - */ - if (of_find_property(csi->dev->of_node, "interconnects", NULL)) { - ret = of_dma_configure(csi->dev, csi->dev->of_node, true); - if (ret) - return ret; - } else { - /* - * XXX(hch): this has no business in a driver and needs to move - * to the device tree. - */ -#ifdef PHYS_PFN_OFFSET - ret = dma_direct_set_offset(csi->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret) - return ret; -#endif - } - csi->mdev.dev = csi->dev; strscpy(csi->mdev.model, "Allwinner Video Capture Device", sizeof(csi->mdev.model)); -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:09 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:09 +0100 Subject: [PATCH 5/7] media: sun6i: Remove the MBUS quirks In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-6-maxime@cerno.tech> Now that the MBUS quirks are applied by our global notifier, we can remove them from our CSI driver for the A31. Suggested-by: Christoph Hellwig Signed-off-by: Maxime Ripard --- .../media/platform/sunxi/sun6i-csi/sun6i_csi.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index e69e14379fc6..27935f1e9555 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -881,14 +881,6 @@ static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev, return 0; } -/* - * PHYS_OFFSET isn't available on all architectures. In order to - * accommodate for COMPILE_TEST, let's define it to something dumb. - */ -#if defined(CONFIG_COMPILE_TEST) && !defined(PHYS_OFFSET) -#define PHYS_OFFSET 0 -#endif - static int sun6i_csi_probe(struct platform_device *pdev) { struct sun6i_csi_dev *sdev; @@ -899,15 +891,6 @@ static int sun6i_csi_probe(struct platform_device *pdev) return -ENOMEM; sdev->dev = &pdev->dev; - /* - * The DMA bus has the memory mapped at 0. - * - * XXX(hch): this has no business in a driver and needs to move - * to the device tree. - */ - ret = dma_direct_set_offset(sdev->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret) - return ret; ret = sun6i_csi_resource_request(sdev, pdev); if (ret) -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:10 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:10 +0100 Subject: [PATCH 6/7] media: cedrus: Remove the MBUS quirks In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-7-maxime@cerno.tech> Now that the MBUS quirks are applied by our global notifier, we can remove them from Cedrus. Since the only quirk was whether or not we had to apply that DMA quirk, we can also remove the quirks infrastructure. Suggested-by: Christoph Hellwig Signed-off-by: Maxime Ripard --- drivers/staging/media/sunxi/cedrus/cedrus.c | 1 - drivers/staging/media/sunxi/cedrus/cedrus.h | 3 --- drivers/staging/media/sunxi/cedrus/cedrus_hw.c | 18 ------------------ 3 files changed, 22 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index e0e35502e34a..d5fca10ea5b4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -523,7 +523,6 @@ static const struct cedrus_variant sun50i_h5_cedrus_variant = { static const struct cedrus_variant sun50i_h6_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_H265_DEC, - .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .mod_rate = 600000000, }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 93c843ae14bb..626090a5811c 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -29,8 +29,6 @@ #define CEDRUS_CAPABILITY_UNTILED BIT(0) #define CEDRUS_CAPABILITY_H265_DEC BIT(1) -#define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) - enum cedrus_codec { CEDRUS_CODEC_MPEG2, CEDRUS_CODEC_H264, @@ -150,7 +148,6 @@ struct cedrus_dec_ops { struct cedrus_variant { unsigned int capabilities; - unsigned int quirks; unsigned int mod_rate; }; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index bcf050a04ffc..286c7fe844c3 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -222,24 +222,6 @@ int cedrus_hw_probe(struct cedrus_dev *dev) return ret; } - /* - * The VPU is only able to handle bus addresses so we have to subtract - * the RAM offset to the physcal addresses. - * - * This information will eventually be obtained from device-tree. - * - * XXX(hch): this has no business in a driver and needs to move - * to the device tree. - */ - -#ifdef PHYS_PFN_OFFSET - if (!(variant->quirks & CEDRUS_QUIRK_NO_DMA_OFFSET)) { - ret = dma_direct_set_offset(dev->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret) - return ret; - } -#endif - ret = of_reserved_mem_device_init(dev->dev); if (ret && ret != -ENODEV) { dev_err(dev->dev, "Failed to reserve memory\n"); -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:07 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:07 +0100 Subject: [PATCH 3/7] drm/sun4i: backend: Remove the MBUS quirks In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-4-maxime@cerno.tech> Now that the MBUS quirks are applied by our global notifier, we can remove them from our DRM driver. Suggested-by: Christoph Hellwig Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 55960cbb1019..522e51a404cc 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -805,25 +805,6 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, ret = of_dma_configure(drm->dev, dev->of_node, true); if (ret) return ret; - } else { - /* - * If we don't have the interconnect property, most likely - * because of an old DT, we need to set the DMA offset by hand - * on our device since the RAM mapping is at 0 for the DMA bus, - * unlike the CPU. - * - * XXX(hch): this has no business in a driver and needs to move - * to the device tree. - * - * If we have two subsequent calls to dma_direct_set_offset - * returns -EINVAL. Unfortunately, this happens when we have two - * backends in the system, and will result in the driver - * reporting an error while it has been setup properly before. - * Ignore EINVAL, but it should really be removed eventually. - */ - ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret && ret != -EINVAL) - return ret; } backend->engine.node = dev->of_node; -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:11 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:11 +0100 Subject: [PATCH 7/7] media: sun8i-di: Remove the call to of_dma_configure In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-8-maxime@cerno.tech> of_dma_configure is called by the core before probe gets called so this is redundant. Signed-off-by: Maxime Ripard --- drivers/media/platform/sunxi/sun8i-di/sun8i-di.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c index ba5d07886607..ed863bf5ea80 100644 --- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c +++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c @@ -825,10 +825,6 @@ static int deinterlace_probe(struct platform_device *pdev) return ret; } - ret = of_dma_configure(dev->dev, dev->dev->of_node, true); - if (ret) - return ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dev->base)) -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:05 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:05 +0100 Subject: [PATCH 1/7] drm/sun4i: backend: Fix probe failure with multiple backends In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-2-maxime@cerno.tech> Commit e0d072782c73 ("dma-mapping: introduce DMA range map, supplanting dma_pfn_offset") introduced a regression in our code since the second backed to probe will now get -EINVAL back from dma_direct_set_offset and will prevent the entire DRM device from probing. Ignore -EINVAL as a temporary measure to get it back working, before removing that call entirely. Fixes: e0d072782c73 ("dma-mapping: introduce DMA range map, supplanting dma_pfn_offset") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 77497b45f9a2..55960cbb1019 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -814,9 +814,15 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, * * XXX(hch): this has no business in a driver and needs to move * to the device tree. + * + * If we have two subsequent calls to dma_direct_set_offset + * returns -EINVAL. Unfortunately, this happens when we have two + * backends in the system, and will result in the driver + * reporting an error while it has been setup properly before. + * Ignore EINVAL, but it should really be removed eventually. */ ret = dma_direct_set_offset(drm->dev, PHYS_OFFSET, 0, SZ_4G); - if (ret) + if (ret && ret != -EINVAL) return ret; } -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:04 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:04 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset Message-ID: <20201106151411.321743-1-maxime@cerno.tech> Hi, Here's an attempt to removing the dma_direct_set_offset calls we have in numerous drivers and move all those quirks into a global notifier as suggested by Robin. Let me know what you think, Maxime Maxime Ripard (7): drm/sun4i: backend: Fix probe failure with multiple backends soc: sunxi: Deal with the MBUS DMA offsets in a central place drm/sun4i: backend: Remove the MBUS quirks media: sun4i: Remove the MBUS quirks media: sun6i: Remove the MBUS quirks media: cedrus: Remove the MBUS quirks media: sun8i-di: Remove the call to of_dma_configure drivers/gpu/drm/sun4i/sun4i_backend.c | 13 -- .../platform/sunxi/sun4i-csi/sun4i_csi.c | 27 ---- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 17 --- .../media/platform/sunxi/sun8i-di/sun8i-di.c | 4 - drivers/soc/sunxi/Kconfig | 8 ++ drivers/soc/sunxi/Makefile | 1 + drivers/soc/sunxi/sunxi_mbus.c | 132 ++++++++++++++++++ drivers/staging/media/sunxi/cedrus/cedrus.c | 1 - drivers/staging/media/sunxi/cedrus/cedrus.h | 3 - .../staging/media/sunxi/cedrus/cedrus_hw.c | 18 --- 10 files changed, 141 insertions(+), 83 deletions(-) create mode 100644 drivers/soc/sunxi/sunxi_mbus.c -- 2.28.0 From maxime at cerno.tech Fri Nov 6 15:14:06 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Fri, 6 Nov 2020 16:14:06 +0100 Subject: [PATCH 2/7] soc: sunxi: Deal with the MBUS DMA offsets in a central place In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106151411.321743-3-maxime@cerno.tech> So far most of the drivers with the MBUS quirks had to duplicate the code to deal with DT compatibility and enforcing the DMA offsets. Let's move for a more maintainable solution by putting everything in a notifier that would take care of setting up the DMA offsets for all the MBUS devices. Suggested-by: Robin Murphy Signed-off-by: Maxime Ripard --- drivers/soc/sunxi/Kconfig | 8 ++ drivers/soc/sunxi/Makefile | 1 + drivers/soc/sunxi/sunxi_mbus.c | 132 +++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 drivers/soc/sunxi/sunxi_mbus.c diff --git a/drivers/soc/sunxi/Kconfig b/drivers/soc/sunxi/Kconfig index f10fd6cae13e..1fef0e711056 100644 --- a/drivers/soc/sunxi/Kconfig +++ b/drivers/soc/sunxi/Kconfig @@ -2,6 +2,14 @@ # # Allwinner sunXi SoC drivers # + +config SUNXI_MBUS + bool + default ARCH_SUNXI + help + Say y to enable the fixups needed to support the Allwinner + MBUS DMA quirks. + config SUNXI_SRAM bool default ARCH_SUNXI diff --git a/drivers/soc/sunxi/Makefile b/drivers/soc/sunxi/Makefile index 7816fbbec387..549159571d4f 100644 --- a/drivers/soc/sunxi/Makefile +++ b/drivers/soc/sunxi/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_SUNXI_MBUS) += sunxi_mbus.o obj-$(CONFIG_SUNXI_SRAM) += sunxi_sram.o diff --git a/drivers/soc/sunxi/sunxi_mbus.c b/drivers/soc/sunxi/sunxi_mbus.c new file mode 100644 index 000000000000..a9d077f73c3a --- /dev/null +++ b/drivers/soc/sunxi/sunxi_mbus.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (C) 2020 Maxime Ripard */ + +#include +#include +#include +#include +#include +#include + +static const char * const sunxi_mbus_devices[] = { + /* + * The display engine virtual devices are not strictly speaking + * connected to the MBUS, but since DRM will perform all the + * memory allocations and DMA operations through that device, we + * need to have the quirk on those devices too. + */ + "allwinner,sun4i-a10-display-engine", + "allwinner,sun5i-a10s-display-engine", + "allwinner,sun5i-a13-display-engine", + "allwinner,sun6i-a31-display-engine", + "allwinner,sun6i-a31s-display-engine", + "allwinner,sun7i-a20-display-engine", + "allwinner,sun8i-a23-display-engine", + "allwinner,sun8i-a33-display-engine", + "allwinner,sun8i-a83t-display-engine", + "allwinner,sun8i-h3-display-engine", + "allwinner,sun8i-r40-display-engine", + "allwinner,sun8i-v3s-display-engine", + "allwinner,sun9i-a80-display-engine", + "allwinner,sun50i-a64-display-engine", + + /* + * And now we have the regular devices connected to the MBUS + * (that we know of). + */ + "allwinner,sun4i-a10-csi1", + "allwinner,sun4i-a10-display-backend", + "allwinner,sun4i-a10-display-frontend", + "allwinner,sun4i-a10-video-engine", + "allwinner,sun5i-a13-display-backend", + "allwinner,sun5i-a13-video-engine", + "allwinner,sun6i-a31-csi", + "allwinner,sun6i-a31-display-backend", + "allwinner,sun7i-a20-csi0", + "allwinner,sun7i-a20-display-backend", + "allwinner,sun7i-a20-display-frontend", + "allwinner,sun7i-a20-video-engine", + "allwinner,sun8i-a23-display-backend", + "allwinner,sun8i-a23-display-frontend", + "allwinner,sun8i-a33-display-backend", + "allwinner,sun8i-a33-display-frontend", + "allwinner,sun8i-a33-video-engine", + "allwinner,sun8i-a83t-csi", + "allwinner,sun8i-h3-csi", + "allwinner,sun8i-h3-video-engine", + "allwinner,sun8i-v3s-csi", + "allwinner,sun9i-a80-display-backend", + "allwinner,sun50i-a64-csi", + "allwinner,sun50i-a64-video-engine", + "allwinner,sun50i-h5-video-engine", + NULL, +}; + +static int sunxi_mbus_notifier(struct notifier_block *nb, + unsigned long event, void *__dev) +{ + struct device *dev = __dev; + int ret; + + if (event != BUS_NOTIFY_ADD_DEVICE) + return NOTIFY_DONE; + + /* + * Only the devices that need a large memory bandwidth do DMA + * directly over the memory bus (called MBUS), instead of going + * through the regular system bus. + */ + if (!of_device_compatible_match(dev->of_node, sunxi_mbus_devices)) + return NOTIFY_DONE; + + /* + * Devices with an interconnects property have the MBUS + * relationship described in their DT and dealt with by + * of_dma_configure, so we can just skip them. + * + * Older DTs or SoCs who are not clearly understood need to set + * that DMA offset though. + */ + if (of_find_property(dev->of_node, "interconnects", NULL)) + return NOTIFY_DONE; + + ret = dma_direct_set_offset(dev, PHYS_OFFSET, 0, SZ_4G); + if (ret) + dev_err(dev, "Couldn't setup our DMA offset: %d\n", ret); + + return NOTIFY_DONE; +} + +static struct notifier_block sunxi_mbus_nb = { + .notifier_call = sunxi_mbus_notifier, +}; + +static const char * const sunxi_mbus_platforms[] __initconst = { + "allwinner,sun4i-a10", + "allwinner,sun5i-a10s", + "allwinner,sun5i-a13", + "allwinner,sun6i-a31", + "allwinner,sun7i-a20", + "allwinner,sun8i-a23", + "allwinner,sun8i-a33", + "allwinner,sun8i-a83t", + "allwinner,sun8i-h3", + "allwinner,sun8i-r40", + "allwinner,sun8i-v3", + "allwinner,sun8i-v3s", + "allwinner,sun9i-a80", + "allwinner,sun50i-a64", + "allwinner,sun50i-h5", + "nextthing,gr8", + NULL, +}; + +static int __init sunxi_mbus_init(void) +{ + if (!of_device_compatible_match(of_root, sunxi_mbus_platforms)) + return 0; + + bus_register_notifier(&platform_bus_type, &sunxi_mbus_nb); + return 0; +} +arch_initcall(sunxi_mbus_init); -- 2.28.0 From wens at kernel.org Fri Nov 6 16:03:28 2020 From: wens at kernel.org (Chen-Yu Tsai) Date: Sat, 7 Nov 2020 00:03:28 +0800 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: Hi, On Fri, Nov 6, 2020 at 11:15 PM Maxime Ripard wrote: > > Hi, > > Here's an attempt to removing the dma_direct_set_offset calls we have in > numerous drivers and move all those quirks into a global notifier as suggested > by Robin. > > Let me know what you think, > Maxime > > Maxime Ripard (7): > drm/sun4i: backend: Fix probe failure with multiple backends > soc: sunxi: Deal with the MBUS DMA offsets in a central place > drm/sun4i: backend: Remove the MBUS quirks > media: sun4i: Remove the MBUS quirks > media: sun6i: Remove the MBUS quirks > media: cedrus: Remove the MBUS quirks > media: sun8i-di: Remove the call to of_dma_configure Whole series looks good to me. Reviewed-by: Chen-Yu Tsai Now the question remaining is how do we merge this series so that the notifier gets merged before all the code dealing with the MBUS quirk gets removed. > drivers/gpu/drm/sun4i/sun4i_backend.c | 13 -- > .../platform/sunxi/sun4i-csi/sun4i_csi.c | 27 ---- > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 17 --- > .../media/platform/sunxi/sun8i-di/sun8i-di.c | 4 - > drivers/soc/sunxi/Kconfig | 8 ++ > drivers/soc/sunxi/Makefile | 1 + > drivers/soc/sunxi/sunxi_mbus.c | 132 ++++++++++++++++++ > drivers/staging/media/sunxi/cedrus/cedrus.c | 1 - > drivers/staging/media/sunxi/cedrus/cedrus.h | 3 - > .../staging/media/sunxi/cedrus/cedrus_hw.c | 18 --- > 10 files changed, 141 insertions(+), 83 deletions(-) > create mode 100644 drivers/soc/sunxi/sunxi_mbus.c > > -- > 2.28.0 > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel From hch at lst.de Fri Nov 6 16:07:37 2020 From: hch at lst.de (Christoph Hellwig) Date: Fri, 6 Nov 2020 17:07:37 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <20201106160737.GA31913@lst.de> Thanks, this looks good to me: Reviewed-by: Christoph Hellwig Can you include this patch at the end of your series to that it gets picked up with the other patches? --- >From 5963f88d365367fe74d477b8420d34562d684406 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 6 Nov 2020 17:02:17 +0100 Subject: dma-mapping: remove the dma_direct_set_offset export Drop the dma_direct_set_offset export and move the declaration to dma-map-ops.h now that the Allwinner drivers have stopped calling it. Signed-off-by: Christoph Hellwig --- arch/arm/mach-keystone/keystone.c | 2 +- arch/arm/mach-omap1/usb.c | 2 +- arch/sh/drivers/pci/pcie-sh7786.c | 2 +- arch/x86/pci/sta2x11-fixup.c | 3 ++- include/linux/dma-map-ops.h | 3 +++ include/linux/dma-mapping.h | 7 ------- kernel/dma/direct.c | 1 - 7 files changed, 8 insertions(+), 12 deletions(-) diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c index 09a65c2dfd7327..cd711bfc591f21 100644 --- a/arch/arm/mach-keystone/keystone.c +++ b/arch/arm/mach-keystone/keystone.c @@ -8,7 +8,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-omap1/usb.c b/arch/arm/mach-omap1/usb.c index ba8566204ea9f4..86d3b3c157af44 100644 --- a/arch/arm/mach-omap1/usb.c +++ b/arch/arm/mach-omap1/usb.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/drivers/pci/pcie-sh7786.c b/arch/sh/drivers/pci/pcie-sh7786.c index 4468289ab2cac7..4d499476c33ad6 100644 --- a/arch/sh/drivers/pci/pcie-sh7786.c +++ b/arch/sh/drivers/pci/pcie-sh7786.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/pci/sta2x11-fixup.c b/arch/x86/pci/sta2x11-fixup.c index 5701d5ba3df4ba..7d25256918543f 100644 --- a/arch/x86/pci/sta2x11-fixup.c +++ b/arch/x86/pci/sta2x11-fixup.c @@ -11,7 +11,8 @@ #include #include #include -#include +#include +#include #include #define STA2X11_SWIOTLB_SIZE (4*1024*1024) diff --git a/include/linux/dma-map-ops.h b/include/linux/dma-map-ops.h index a5f89fc4d6df16..03925e438ec3e5 100644 --- a/include/linux/dma-map-ops.h +++ b/include/linux/dma-map-ops.h @@ -226,6 +226,9 @@ struct page *dma_alloc_from_pool(struct device *dev, size_t size, bool (*phys_addr_ok)(struct device *, phys_addr_t, size_t)); bool dma_free_from_pool(struct device *dev, void *start, size_t size); +int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, + dma_addr_t dma_start, u64 size); + #ifdef CONFIG_ARCH_HAS_DMA_COHERENCE_H #include #elif defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \ diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index 2aaed35b556df4..2e49996a8f391a 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -558,11 +558,4 @@ static inline int dma_mmap_wc(struct device *dev, #define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) #endif -/* - * Legacy interface to set up the dma offset map. Drivers really should not - * actually use it, but we have a few legacy cases left. - */ -int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, - dma_addr_t dma_start, u64 size); - #endif /* _LINUX_DMA_MAPPING_H */ diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c index 06c111544f61d6..002268262c9ad8 100644 --- a/kernel/dma/direct.c +++ b/kernel/dma/direct.c @@ -547,4 +547,3 @@ int dma_direct_set_offset(struct device *dev, phys_addr_t cpu_start, dev->dma_range_map = map; return 0; } -EXPORT_SYMBOL_GPL(dma_direct_set_offset); -- 2.28.0 From christian.gromm at microchip.com Fri Nov 6 16:30:54 2020 From: christian.gromm at microchip.com (Christian Gromm) Date: Fri, 6 Nov 2020 17:30:54 +0100 Subject: [PATCH v2] drivers: most: add ALSA sound driver Message-ID: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> This patch moves the ALSA sound driver out of the staging area and adds it to the stable part of the MOST driver. Modifications to the Makefiles and Kconfigs are done accordingly to not break the build. Signed-off-by: Christian Gromm --- v2: Reported-by: Greg Kroah-Hartman submitted patch that fixes issue found during code audit to staging version first to be able to resend single patch that adds the driver. The patch series included: - use swabXX functions of kernel drivers/most/Kconfig | 10 + drivers/most/Makefile | 1 + drivers/most/most_snd.c | 743 ++++++++++++++++++++++++++++++++++++ drivers/staging/most/Kconfig | 2 - drivers/staging/most/Makefile | 1 - drivers/staging/most/sound/Kconfig | 14 - drivers/staging/most/sound/Makefile | 4 - drivers/staging/most/sound/sound.c | 743 ------------------------------------ 8 files changed, 754 insertions(+), 764 deletions(-) create mode 100644 drivers/most/most_snd.c delete mode 100644 drivers/staging/most/sound/Kconfig delete mode 100644 drivers/staging/most/sound/Makefile delete mode 100644 drivers/staging/most/sound/sound.c diff --git a/drivers/most/Kconfig b/drivers/most/Kconfig index ebfe84e..4b8145b 100644 --- a/drivers/most/Kconfig +++ b/drivers/most/Kconfig @@ -32,4 +32,14 @@ config MOST_CDEV To compile this driver as a module, choose M here: the module will be called most_cdev. + +config MOST_SND + tristate "Sound" + depends on SND + select SND_PCM + help + Say Y here if you want to commumicate via ALSA/sound devices. + + To compile this driver as a module, choose M here: the + module will be called most_sound. endif diff --git a/drivers/most/Makefile b/drivers/most/Makefile index 8b53ca4..60db6cd 100644 --- a/drivers/most/Makefile +++ b/drivers/most/Makefile @@ -5,3 +5,4 @@ most_core-y := core.o \ obj-$(CONFIG_MOST_USB_HDM) += most_usb.o obj-$(CONFIG_MOST_CDEV) += most_cdev.o +obj-$(CONFIG_MOST_SND) += most_snd.o diff --git a/drivers/most/most_snd.c b/drivers/most/most_snd.c new file mode 100644 index 0000000..3a1a590 --- /dev/null +++ b/drivers/most/most_snd.c @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * sound.c - Sound component for Mostcore + * + * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "sound" +#define STRING_SIZE 80 + +static struct most_component comp; + +/** + * struct channel - private structure to keep channel specific data + * @substream: stores the substream structure + * @iface: interface for which the channel belongs to + * @cfg: channel configuration + * @card: registered sound card + * @list: list for private use + * @id: channel index + * @period_pos: current period position (ring buffer) + * @buffer_pos: current buffer position (ring buffer) + * @is_stream_running: identifies whether a stream is running or not + * @opened: set when the stream is opened + * @playback_task: playback thread + * @playback_waitq: waitq used by playback thread + */ +struct channel { + struct snd_pcm_substream *substream; + struct snd_pcm_hardware pcm_hardware; + struct most_interface *iface; + struct most_channel_config *cfg; + struct snd_card *card; + struct list_head list; + int id; + unsigned int period_pos; + unsigned int buffer_pos; + bool is_stream_running; + struct task_struct *playback_task; + wait_queue_head_t playback_waitq; + void (*copy_fn)(void *alsa, void *most, unsigned int bytes); +}; + +struct sound_adapter { + struct list_head dev_list; + struct most_interface *iface; + struct snd_card *card; + struct list_head list; + bool registered; + int pcm_dev_idx; +}; + +static struct list_head adpt_list; + +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ + SNDRV_PCM_INFO_MMAP_VALID | \ + SNDRV_PCM_INFO_BATCH | \ + SNDRV_PCM_INFO_INTERLEAVED | \ + SNDRV_PCM_INFO_BLOCK_TRANSFER) + +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < (bytes / 2)) { + dest[i] = swab16(source[i]); + i++; + } +} + +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes - 2) { + dest[i] = source[i + 2]; + dest[i + 1] = source[i + 1]; + dest[i + 2] = source[i]; + i += 3; + } +} + +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) +{ + unsigned int i = 0; + + while (i < bytes / 4) { + dest[i] = swab32(source[i]); + i++; + } +} + +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(most, alsa, bytes); +} + +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(most, alsa, bytes); +} + +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(most, alsa, bytes); +} + +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(most, alsa, bytes); +} + +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) +{ + memcpy(alsa, most, bytes); +} + +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) +{ + swap_copy16(alsa, most, bytes); +} + +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) +{ + swap_copy24(alsa, most, bytes); +} + +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) +{ + swap_copy32(alsa, most, bytes); +} + +/** + * get_channel - get pointer to channel + * @iface: interface structure + * @channel_id: channel ID + * + * This traverses the channel list and returns the channel matching the + * ID and interface. + * + * Returns pointer to channel on success or NULL otherwise. + */ +static struct channel *get_channel(struct most_interface *iface, + int channel_id) +{ + struct sound_adapter *adpt = iface->priv; + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { + if ((channel->iface == iface) && (channel->id == channel_id)) + return channel; + } + return NULL; +} + +/** + * copy_data - implements data copying function + * @channel: channel + * @mbo: MBO from core + * + * Copy data from/to ring buffer to/from MBO and update the buffer position + */ +static bool copy_data(struct channel *channel, struct mbo *mbo) +{ + struct snd_pcm_runtime *const runtime = channel->substream->runtime; + unsigned int const frame_bytes = channel->cfg->subbuffer_size; + unsigned int const buffer_size = runtime->buffer_size; + unsigned int frames; + unsigned int fr0; + + if (channel->cfg->direction & MOST_CH_RX) + frames = mbo->processed_length / frame_bytes; + else + frames = mbo->buffer_length / frame_bytes; + fr0 = min(buffer_size - channel->buffer_pos, frames); + + channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, + mbo->virt_address, + fr0 * frame_bytes); + + if (frames > fr0) { + /* wrap around at end of ring buffer */ + channel->copy_fn(runtime->dma_area, + mbo->virt_address + fr0 * frame_bytes, + (frames - fr0) * frame_bytes); + } + + channel->buffer_pos += frames; + if (channel->buffer_pos >= buffer_size) + channel->buffer_pos -= buffer_size; + channel->period_pos += frames; + if (channel->period_pos >= runtime->period_size) { + channel->period_pos -= runtime->period_size; + return true; + } + return false; +} + +/** + * playback_thread - function implements the playback thread + * @data: private data + * + * Thread which does the playback functionality in a loop. It waits for a free + * MBO from mostcore for a particular channel and copy the data from ring buffer + * to MBO. Submit the MBO back to mostcore, after copying the data. + * + * Returns 0 on success or error code otherwise. + */ +static int playback_thread(void *data) +{ + struct channel *const channel = data; + + while (!kthread_should_stop()) { + struct mbo *mbo = NULL; + bool period_elapsed = false; + + wait_event_interruptible( + channel->playback_waitq, + kthread_should_stop() || + (channel->is_stream_running && + (mbo = most_get_mbo(channel->iface, channel->id, + &comp)))); + if (!mbo) + continue; + + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + else + memset(mbo->virt_address, 0, mbo->buffer_length); + + most_submit_mbo(mbo); + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + } + return 0; +} + +/** + * pcm_open - implements open callback function for PCM middle layer + * @substream: pointer to ALSA PCM substream + * + * This is called when a PCM substream is opened. At least, the function should + * initialize the runtime->hw record. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_open(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + int ret; + + channel->substream = substream; + + if (cfg->direction == MOST_CH_TX) { + channel->playback_task = kthread_run(playback_thread, channel, + "most_audio_playback"); + if (IS_ERR(channel->playback_task)) { + pr_err("Couldn't start thread\n"); + return PTR_ERR(channel->playback_task); + } + } + + ret = most_start_channel(channel->iface, channel->id, &comp); + if (ret) { + pr_err("most_start_channel() failed!\n"); + if (cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + return ret; + } + + runtime->hw = channel->pcm_hardware; + return 0; +} + +/** + * pcm_close - implements close callback function for PCM middle layer + * @substream: sub-stream pointer + * + * Obviously, this is called when a PCM substream is closed. Any private + * instance for a PCM substream allocated in the open callback will be + * released here. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_close(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + if (channel->cfg->direction == MOST_CH_TX) + kthread_stop(channel->playback_task); + most_stop_channel(channel->iface, channel->id, &comp); + return 0; +} + +/** + * pcm_prepare - implements prepare callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM is "prepared". Format rate, sample rate, + * etc., can be set here. This callback can be called many times at each setup. + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_prepare(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + struct snd_pcm_runtime *runtime = substream->runtime; + struct most_channel_config *cfg = channel->cfg; + int width = snd_pcm_format_physical_width(runtime->format); + + channel->copy_fn = NULL; + + if (cfg->direction == MOST_CH_TX) { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = alsa_to_most_memcpy; + else if (width == 16) + channel->copy_fn = alsa_to_most_copy16; + else if (width == 24) + channel->copy_fn = alsa_to_most_copy24; + else if (width == 32) + channel->copy_fn = alsa_to_most_copy32; + } else { + if (snd_pcm_format_big_endian(runtime->format) || width == 8) + channel->copy_fn = most_to_alsa_memcpy; + else if (width == 16) + channel->copy_fn = most_to_alsa_copy16; + else if (width == 24) + channel->copy_fn = most_to_alsa_copy24; + else if (width == 32) + channel->copy_fn = most_to_alsa_copy32; + } + + if (!channel->copy_fn) + return -EINVAL; + channel->period_pos = 0; + channel->buffer_pos = 0; + return 0; +} + +/** + * pcm_trigger - implements trigger callback function for PCM middle layer + * @substream: substream pointer + * @cmd: action to perform + * + * This is called when the PCM is started, stopped or paused. The action will be + * specified in the second argument, SNDRV_PCM_TRIGGER_XXX + * + * Returns 0 on success or error code otherwise. + */ +static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct channel *channel = substream->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + channel->is_stream_running = true; + wake_up_interruptible(&channel->playback_waitq); + return 0; + + case SNDRV_PCM_TRIGGER_STOP: + channel->is_stream_running = false; + return 0; + + default: + return -EINVAL; + } + return 0; +} + +/** + * pcm_pointer - implements pointer callback function for PCM middle layer + * @substream: substream pointer + * + * This callback is called when the PCM middle layer inquires the current + * hardware position on the buffer. The position must be returned in frames, + * ranging from 0 to buffer_size-1. + */ +static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) +{ + struct channel *channel = substream->private_data; + + return channel->buffer_pos; +} + +/** + * Initialization of struct snd_pcm_ops + */ +static const struct snd_pcm_ops pcm_ops = { + .open = pcm_open, + .close = pcm_close, + .prepare = pcm_prepare, + .trigger = pcm_trigger, + .pointer = pcm_pointer, +}; + +static int split_arg_list(char *buf, u16 *ch_num, char **sample_res) +{ + char *num; + int ret; + + num = strsep(&buf, "x"); + if (!num) + goto err; + ret = kstrtou16(num, 0, ch_num); + if (ret) + goto err; + *sample_res = strsep(&buf, ".\n"); + if (!*sample_res) + goto err; + return 0; + +err: + pr_err("Bad PCM format\n"); + return -EINVAL; +} + +static const struct sample_resolution_info { + const char *sample_res; + int bytes; + u64 formats; +} sinfo[] = { + { "8", 1, SNDRV_PCM_FMTBIT_S8 }, + { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, + { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, + { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, +}; + +static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, + u16 ch_num, char *sample_res, + struct most_channel_config *cfg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sinfo); i++) { + if (!strcmp(sample_res, sinfo[i].sample_res)) + goto found; + } + pr_err("Unsupported PCM format\n"); + return -EINVAL; + +found: + if (!ch_num) { + pr_err("Bad number of channels\n"); + return -EINVAL; + } + + if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { + pr_err("Audio resolution doesn't fit subbuffer size\n"); + return -EINVAL; + } + + pcm_hw->info = MOST_PCM_INFO; + pcm_hw->rates = SNDRV_PCM_RATE_48000; + pcm_hw->rate_min = 48000; + pcm_hw->rate_max = 48000; + pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; + pcm_hw->period_bytes_min = cfg->buffer_size; + pcm_hw->period_bytes_max = cfg->buffer_size; + pcm_hw->periods_min = 1; + pcm_hw->periods_max = cfg->num_buffers; + pcm_hw->channels_min = ch_num; + pcm_hw->channels_max = ch_num; + pcm_hw->formats = sinfo[i].formats; + return 0; +} + +static void release_adapter(struct sound_adapter *adpt) +{ + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { + list_del(&channel->list); + kfree(channel); + } + if (adpt->card) + snd_card_free(adpt->card); + list_del(&adpt->list); + kfree(adpt); +} + +/** + * audio_probe_channel - probe function of the driver module + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * @cfg: pointer to actual channel configuration + * @arg_list: string that provides the name of the device to be created in /dev + * plus the desired audio resolution + * + * Creates sound card, pcm device, sets pcm ops and registers sound card. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_probe_channel(struct most_interface *iface, int channel_id, + struct most_channel_config *cfg, + char *device_name, char *arg_list) +{ + struct channel *channel; + struct sound_adapter *adpt; + struct snd_pcm *pcm; + int playback_count = 0; + int capture_count = 0; + int ret; + int direction; + u16 ch_num; + char *sample_res; + char arg_list_cpy[STRING_SIZE]; + + if (cfg->data_type != MOST_CH_SYNC) { + pr_err("Incompatible channel type\n"); + return -EINVAL; + } + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); + if (ret < 0) + return ret; + + list_for_each_entry(adpt, &adpt_list, list) { + if (adpt->iface != iface) + continue; + if (adpt->registered) + return -ENOSPC; + adpt->pcm_dev_idx++; + goto skip_adpt_alloc; + } + adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); + if (!adpt) + return -ENOMEM; + + adpt->iface = iface; + INIT_LIST_HEAD(&adpt->dev_list); + iface->priv = adpt; + list_add_tail(&adpt->list, &adpt_list); + ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, + sizeof(*channel), &adpt->card); + if (ret < 0) + goto err_free_adpt; + snprintf(adpt->card->driver, sizeof(adpt->card->driver), + "%s", DRIVER_NAME); + snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), + "Microchip INIC"); + snprintf(adpt->card->longname, sizeof(adpt->card->longname), + "%s at %s", adpt->card->shortname, iface->description); +skip_adpt_alloc: + if (get_channel(iface, channel_id)) { + pr_err("channel (%s:%d) is already linked\n", + iface->description, channel_id); + return -EEXIST; + } + + if (cfg->direction == MOST_CH_TX) { + playback_count = 1; + direction = SNDRV_PCM_STREAM_PLAYBACK; + } else { + capture_count = 1; + direction = SNDRV_PCM_STREAM_CAPTURE; + } + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) { + ret = -ENOMEM; + goto err_free_adpt; + } + channel->card = adpt->card; + channel->cfg = cfg; + channel->iface = iface; + channel->id = channel_id; + init_waitqueue_head(&channel->playback_waitq); + list_add_tail(&channel->list, &adpt->dev_list); + + ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, + cfg); + if (ret) + goto err_free_adpt; + + ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, + playback_count, capture_count, &pcm); + + if (ret < 0) + goto err_free_adpt; + + pcm->private_data = channel; + strscpy(pcm->name, device_name, sizeof(pcm->name)); + snd_pcm_set_ops(pcm, direction, &pcm_ops); + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); + return 0; + +err_free_adpt: + release_adapter(adpt); + return ret; +} + +static int audio_create_sound_card(void) +{ + int ret; + struct sound_adapter *adpt; + + list_for_each_entry(adpt, &adpt_list, list) { + if (!adpt->registered) + goto adpt_alloc; + } + return -ENODEV; +adpt_alloc: + ret = snd_card_register(adpt->card); + if (ret < 0) { + release_adapter(adpt); + return ret; + } + adpt->registered = true; + return 0; +} + +/** + * audio_disconnect_channel - function to disconnect a channel + * @iface: pointer to interface instance + * @channel_id: channel index + * + * This frees allocated memory and removes the sound card from ALSA + * + * Returns 0 on success or error code otherwise. + */ +static int audio_disconnect_channel(struct most_interface *iface, + int channel_id) +{ + struct channel *channel; + struct sound_adapter *adpt = iface->priv; + + channel = get_channel(iface, channel_id); + if (!channel) + return -EINVAL; + + list_del(&channel->list); + + kfree(channel); + if (list_empty(&adpt->dev_list)) + release_adapter(adpt); + return 0; +} + +/** + * audio_rx_completion - completion handler for rx channels + * @mbo: pointer to buffer object that has completed + * + * This searches for the channel this MBO belongs to and copy the data from MBO + * to ring buffer + * + * Returns 0 on success or error code otherwise. + */ +static int audio_rx_completion(struct mbo *mbo) +{ + struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); + bool period_elapsed = false; + + if (!channel) + return -EINVAL; + if (channel->is_stream_running) + period_elapsed = copy_data(channel, mbo); + most_put_mbo(mbo); + if (period_elapsed) + snd_pcm_period_elapsed(channel->substream); + return 0; +} + +/** + * audio_tx_completion - completion handler for tx channels + * @iface: pointer to interface instance + * @channel_id: channel index/ID + * + * This searches the channel that belongs to this combination of interface + * pointer and channel ID and wakes a process sitting in the wait queue of + * this channel. + * + * Returns 0 on success or error code otherwise. + */ +static int audio_tx_completion(struct most_interface *iface, int channel_id) +{ + struct channel *channel = get_channel(iface, channel_id); + + if (!channel) + return -EINVAL; + + wake_up_interruptible(&channel->playback_waitq); + return 0; +} + +/** + * Initialization of the struct most_component + */ +static struct most_component comp = { + .mod = THIS_MODULE, + .name = DRIVER_NAME, + .probe_channel = audio_probe_channel, + .disconnect_channel = audio_disconnect_channel, + .rx_completion = audio_rx_completion, + .tx_completion = audio_tx_completion, + .cfg_complete = audio_create_sound_card, +}; + +static int __init audio_init(void) +{ + int ret; + + INIT_LIST_HEAD(&adpt_list); + + ret = most_register_component(&comp); + if (ret) { + pr_err("Failed to register %s\n", comp.name); + return ret; + } + ret = most_register_configfs_subsys(&comp); + if (ret) { + pr_err("Failed to register %s configfs subsys\n", comp.name); + most_deregister_component(&comp); + } + return ret; +} + +static void __exit audio_exit(void) +{ + most_deregister_configfs_subsys(&comp); + most_deregister_component(&comp); +} + +module_init(audio_init); +module_exit(audio_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Christian Gromm "); +MODULE_DESCRIPTION("Sound Component Module for Mostcore"); diff --git a/drivers/staging/most/Kconfig b/drivers/staging/most/Kconfig index 535e6de..6f420cb 100644 --- a/drivers/staging/most/Kconfig +++ b/drivers/staging/most/Kconfig @@ -20,8 +20,6 @@ if MOST_COMPONENTS source "drivers/staging/most/net/Kconfig" -source "drivers/staging/most/sound/Kconfig" - source "drivers/staging/most/video/Kconfig" source "drivers/staging/most/dim2/Kconfig" diff --git a/drivers/staging/most/Makefile b/drivers/staging/most/Makefile index be94673..8b3fc5a 100644 --- a/drivers/staging/most/Makefile +++ b/drivers/staging/most/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MOST_NET) += net/ -obj-$(CONFIG_MOST_SOUND) += sound/ obj-$(CONFIG_MOST_VIDEO) += video/ obj-$(CONFIG_MOST_DIM2) += dim2/ obj-$(CONFIG_MOST_I2C) += i2c/ diff --git a/drivers/staging/most/sound/Kconfig b/drivers/staging/most/sound/Kconfig deleted file mode 100644 index ad9f782..0000000 --- a/drivers/staging/most/sound/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# MOST ALSA configuration -# - -config MOST_SOUND - tristate "Sound" - depends on SND - select SND_PCM - help - Say Y here if you want to commumicate via ALSA/sound devices. - - To compile this driver as a module, choose M here: the - module will be called most_sound. diff --git a/drivers/staging/most/sound/Makefile b/drivers/staging/most/sound/Makefile deleted file mode 100644 index f0cd9d8..0000000 --- a/drivers/staging/most/sound/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MOST_SOUND) += most_sound.o - -most_sound-objs := sound.o diff --git a/drivers/staging/most/sound/sound.c b/drivers/staging/most/sound/sound.c deleted file mode 100644 index 3a1a590..0000000 --- a/drivers/staging/most/sound/sound.c +++ /dev/null @@ -1,743 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * sound.c - Sound component for Mostcore - * - * Copyright (C) 2015 Microchip Technology Germany II GmbH & Co. KG - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "sound" -#define STRING_SIZE 80 - -static struct most_component comp; - -/** - * struct channel - private structure to keep channel specific data - * @substream: stores the substream structure - * @iface: interface for which the channel belongs to - * @cfg: channel configuration - * @card: registered sound card - * @list: list for private use - * @id: channel index - * @period_pos: current period position (ring buffer) - * @buffer_pos: current buffer position (ring buffer) - * @is_stream_running: identifies whether a stream is running or not - * @opened: set when the stream is opened - * @playback_task: playback thread - * @playback_waitq: waitq used by playback thread - */ -struct channel { - struct snd_pcm_substream *substream; - struct snd_pcm_hardware pcm_hardware; - struct most_interface *iface; - struct most_channel_config *cfg; - struct snd_card *card; - struct list_head list; - int id; - unsigned int period_pos; - unsigned int buffer_pos; - bool is_stream_running; - struct task_struct *playback_task; - wait_queue_head_t playback_waitq; - void (*copy_fn)(void *alsa, void *most, unsigned int bytes); -}; - -struct sound_adapter { - struct list_head dev_list; - struct most_interface *iface; - struct snd_card *card; - struct list_head list; - bool registered; - int pcm_dev_idx; -}; - -static struct list_head adpt_list; - -#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ - SNDRV_PCM_INFO_MMAP_VALID | \ - SNDRV_PCM_INFO_BATCH | \ - SNDRV_PCM_INFO_INTERLEAVED | \ - SNDRV_PCM_INFO_BLOCK_TRANSFER) - -static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < (bytes / 2)) { - dest[i] = swab16(source[i]); - i++; - } -} - -static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < bytes - 2) { - dest[i] = source[i + 2]; - dest[i + 1] = source[i + 1]; - dest[i + 2] = source[i]; - i += 3; - } -} - -static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) -{ - unsigned int i = 0; - - while (i < bytes / 4) { - dest[i] = swab32(source[i]); - i++; - } -} - -static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) -{ - memcpy(most, alsa, bytes); -} - -static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) -{ - swap_copy16(most, alsa, bytes); -} - -static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) -{ - swap_copy24(most, alsa, bytes); -} - -static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) -{ - swap_copy32(most, alsa, bytes); -} - -static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) -{ - memcpy(alsa, most, bytes); -} - -static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) -{ - swap_copy16(alsa, most, bytes); -} - -static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) -{ - swap_copy24(alsa, most, bytes); -} - -static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) -{ - swap_copy32(alsa, most, bytes); -} - -/** - * get_channel - get pointer to channel - * @iface: interface structure - * @channel_id: channel ID - * - * This traverses the channel list and returns the channel matching the - * ID and interface. - * - * Returns pointer to channel on success or NULL otherwise. - */ -static struct channel *get_channel(struct most_interface *iface, - int channel_id) -{ - struct sound_adapter *adpt = iface->priv; - struct channel *channel, *tmp; - - list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { - if ((channel->iface == iface) && (channel->id == channel_id)) - return channel; - } - return NULL; -} - -/** - * copy_data - implements data copying function - * @channel: channel - * @mbo: MBO from core - * - * Copy data from/to ring buffer to/from MBO and update the buffer position - */ -static bool copy_data(struct channel *channel, struct mbo *mbo) -{ - struct snd_pcm_runtime *const runtime = channel->substream->runtime; - unsigned int const frame_bytes = channel->cfg->subbuffer_size; - unsigned int const buffer_size = runtime->buffer_size; - unsigned int frames; - unsigned int fr0; - - if (channel->cfg->direction & MOST_CH_RX) - frames = mbo->processed_length / frame_bytes; - else - frames = mbo->buffer_length / frame_bytes; - fr0 = min(buffer_size - channel->buffer_pos, frames); - - channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, - mbo->virt_address, - fr0 * frame_bytes); - - if (frames > fr0) { - /* wrap around at end of ring buffer */ - channel->copy_fn(runtime->dma_area, - mbo->virt_address + fr0 * frame_bytes, - (frames - fr0) * frame_bytes); - } - - channel->buffer_pos += frames; - if (channel->buffer_pos >= buffer_size) - channel->buffer_pos -= buffer_size; - channel->period_pos += frames; - if (channel->period_pos >= runtime->period_size) { - channel->period_pos -= runtime->period_size; - return true; - } - return false; -} - -/** - * playback_thread - function implements the playback thread - * @data: private data - * - * Thread which does the playback functionality in a loop. It waits for a free - * MBO from mostcore for a particular channel and copy the data from ring buffer - * to MBO. Submit the MBO back to mostcore, after copying the data. - * - * Returns 0 on success or error code otherwise. - */ -static int playback_thread(void *data) -{ - struct channel *const channel = data; - - while (!kthread_should_stop()) { - struct mbo *mbo = NULL; - bool period_elapsed = false; - - wait_event_interruptible( - channel->playback_waitq, - kthread_should_stop() || - (channel->is_stream_running && - (mbo = most_get_mbo(channel->iface, channel->id, - &comp)))); - if (!mbo) - continue; - - if (channel->is_stream_running) - period_elapsed = copy_data(channel, mbo); - else - memset(mbo->virt_address, 0, mbo->buffer_length); - - most_submit_mbo(mbo); - if (period_elapsed) - snd_pcm_period_elapsed(channel->substream); - } - return 0; -} - -/** - * pcm_open - implements open callback function for PCM middle layer - * @substream: pointer to ALSA PCM substream - * - * This is called when a PCM substream is opened. At least, the function should - * initialize the runtime->hw record. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_open(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct most_channel_config *cfg = channel->cfg; - int ret; - - channel->substream = substream; - - if (cfg->direction == MOST_CH_TX) { - channel->playback_task = kthread_run(playback_thread, channel, - "most_audio_playback"); - if (IS_ERR(channel->playback_task)) { - pr_err("Couldn't start thread\n"); - return PTR_ERR(channel->playback_task); - } - } - - ret = most_start_channel(channel->iface, channel->id, &comp); - if (ret) { - pr_err("most_start_channel() failed!\n"); - if (cfg->direction == MOST_CH_TX) - kthread_stop(channel->playback_task); - return ret; - } - - runtime->hw = channel->pcm_hardware; - return 0; -} - -/** - * pcm_close - implements close callback function for PCM middle layer - * @substream: sub-stream pointer - * - * Obviously, this is called when a PCM substream is closed. Any private - * instance for a PCM substream allocated in the open callback will be - * released here. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_close(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - - if (channel->cfg->direction == MOST_CH_TX) - kthread_stop(channel->playback_task); - most_stop_channel(channel->iface, channel->id, &comp); - return 0; -} - -/** - * pcm_prepare - implements prepare callback function for PCM middle layer - * @substream: substream pointer - * - * This callback is called when the PCM is "prepared". Format rate, sample rate, - * etc., can be set here. This callback can be called many times at each setup. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_prepare(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - struct snd_pcm_runtime *runtime = substream->runtime; - struct most_channel_config *cfg = channel->cfg; - int width = snd_pcm_format_physical_width(runtime->format); - - channel->copy_fn = NULL; - - if (cfg->direction == MOST_CH_TX) { - if (snd_pcm_format_big_endian(runtime->format) || width == 8) - channel->copy_fn = alsa_to_most_memcpy; - else if (width == 16) - channel->copy_fn = alsa_to_most_copy16; - else if (width == 24) - channel->copy_fn = alsa_to_most_copy24; - else if (width == 32) - channel->copy_fn = alsa_to_most_copy32; - } else { - if (snd_pcm_format_big_endian(runtime->format) || width == 8) - channel->copy_fn = most_to_alsa_memcpy; - else if (width == 16) - channel->copy_fn = most_to_alsa_copy16; - else if (width == 24) - channel->copy_fn = most_to_alsa_copy24; - else if (width == 32) - channel->copy_fn = most_to_alsa_copy32; - } - - if (!channel->copy_fn) - return -EINVAL; - channel->period_pos = 0; - channel->buffer_pos = 0; - return 0; -} - -/** - * pcm_trigger - implements trigger callback function for PCM middle layer - * @substream: substream pointer - * @cmd: action to perform - * - * This is called when the PCM is started, stopped or paused. The action will be - * specified in the second argument, SNDRV_PCM_TRIGGER_XXX - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct channel *channel = substream->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - channel->is_stream_running = true; - wake_up_interruptible(&channel->playback_waitq); - return 0; - - case SNDRV_PCM_TRIGGER_STOP: - channel->is_stream_running = false; - return 0; - - default: - return -EINVAL; - } - return 0; -} - -/** - * pcm_pointer - implements pointer callback function for PCM middle layer - * @substream: substream pointer - * - * This callback is called when the PCM middle layer inquires the current - * hardware position on the buffer. The position must be returned in frames, - * ranging from 0 to buffer_size-1. - */ -static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) -{ - struct channel *channel = substream->private_data; - - return channel->buffer_pos; -} - -/** - * Initialization of struct snd_pcm_ops - */ -static const struct snd_pcm_ops pcm_ops = { - .open = pcm_open, - .close = pcm_close, - .prepare = pcm_prepare, - .trigger = pcm_trigger, - .pointer = pcm_pointer, -}; - -static int split_arg_list(char *buf, u16 *ch_num, char **sample_res) -{ - char *num; - int ret; - - num = strsep(&buf, "x"); - if (!num) - goto err; - ret = kstrtou16(num, 0, ch_num); - if (ret) - goto err; - *sample_res = strsep(&buf, ".\n"); - if (!*sample_res) - goto err; - return 0; - -err: - pr_err("Bad PCM format\n"); - return -EINVAL; -} - -static const struct sample_resolution_info { - const char *sample_res; - int bytes; - u64 formats; -} sinfo[] = { - { "8", 1, SNDRV_PCM_FMTBIT_S8 }, - { "16", 2, SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE }, - { "24", 3, SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE }, - { "32", 4, SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE }, -}; - -static int audio_set_hw_params(struct snd_pcm_hardware *pcm_hw, - u16 ch_num, char *sample_res, - struct most_channel_config *cfg) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(sinfo); i++) { - if (!strcmp(sample_res, sinfo[i].sample_res)) - goto found; - } - pr_err("Unsupported PCM format\n"); - return -EINVAL; - -found: - if (!ch_num) { - pr_err("Bad number of channels\n"); - return -EINVAL; - } - - if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { - pr_err("Audio resolution doesn't fit subbuffer size\n"); - return -EINVAL; - } - - pcm_hw->info = MOST_PCM_INFO; - pcm_hw->rates = SNDRV_PCM_RATE_48000; - pcm_hw->rate_min = 48000; - pcm_hw->rate_max = 48000; - pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; - pcm_hw->period_bytes_min = cfg->buffer_size; - pcm_hw->period_bytes_max = cfg->buffer_size; - pcm_hw->periods_min = 1; - pcm_hw->periods_max = cfg->num_buffers; - pcm_hw->channels_min = ch_num; - pcm_hw->channels_max = ch_num; - pcm_hw->formats = sinfo[i].formats; - return 0; -} - -static void release_adapter(struct sound_adapter *adpt) -{ - struct channel *channel, *tmp; - - list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { - list_del(&channel->list); - kfree(channel); - } - if (adpt->card) - snd_card_free(adpt->card); - list_del(&adpt->list); - kfree(adpt); -} - -/** - * audio_probe_channel - probe function of the driver module - * @iface: pointer to interface instance - * @channel_id: channel index/ID - * @cfg: pointer to actual channel configuration - * @arg_list: string that provides the name of the device to be created in /dev - * plus the desired audio resolution - * - * Creates sound card, pcm device, sets pcm ops and registers sound card. - * - * Returns 0 on success or error code otherwise. - */ -static int audio_probe_channel(struct most_interface *iface, int channel_id, - struct most_channel_config *cfg, - char *device_name, char *arg_list) -{ - struct channel *channel; - struct sound_adapter *adpt; - struct snd_pcm *pcm; - int playback_count = 0; - int capture_count = 0; - int ret; - int direction; - u16 ch_num; - char *sample_res; - char arg_list_cpy[STRING_SIZE]; - - if (cfg->data_type != MOST_CH_SYNC) { - pr_err("Incompatible channel type\n"); - return -EINVAL; - } - strlcpy(arg_list_cpy, arg_list, STRING_SIZE); - ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); - if (ret < 0) - return ret; - - list_for_each_entry(adpt, &adpt_list, list) { - if (adpt->iface != iface) - continue; - if (adpt->registered) - return -ENOSPC; - adpt->pcm_dev_idx++; - goto skip_adpt_alloc; - } - adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); - if (!adpt) - return -ENOMEM; - - adpt->iface = iface; - INIT_LIST_HEAD(&adpt->dev_list); - iface->priv = adpt; - list_add_tail(&adpt->list, &adpt_list); - ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, - sizeof(*channel), &adpt->card); - if (ret < 0) - goto err_free_adpt; - snprintf(adpt->card->driver, sizeof(adpt->card->driver), - "%s", DRIVER_NAME); - snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), - "Microchip INIC"); - snprintf(adpt->card->longname, sizeof(adpt->card->longname), - "%s at %s", adpt->card->shortname, iface->description); -skip_adpt_alloc: - if (get_channel(iface, channel_id)) { - pr_err("channel (%s:%d) is already linked\n", - iface->description, channel_id); - return -EEXIST; - } - - if (cfg->direction == MOST_CH_TX) { - playback_count = 1; - direction = SNDRV_PCM_STREAM_PLAYBACK; - } else { - capture_count = 1; - direction = SNDRV_PCM_STREAM_CAPTURE; - } - channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (!channel) { - ret = -ENOMEM; - goto err_free_adpt; - } - channel->card = adpt->card; - channel->cfg = cfg; - channel->iface = iface; - channel->id = channel_id; - init_waitqueue_head(&channel->playback_waitq); - list_add_tail(&channel->list, &adpt->dev_list); - - ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, - cfg); - if (ret) - goto err_free_adpt; - - ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, - playback_count, capture_count, &pcm); - - if (ret < 0) - goto err_free_adpt; - - pcm->private_data = channel; - strscpy(pcm->name, device_name, sizeof(pcm->name)); - snd_pcm_set_ops(pcm, direction, &pcm_ops); - snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); - return 0; - -err_free_adpt: - release_adapter(adpt); - return ret; -} - -static int audio_create_sound_card(void) -{ - int ret; - struct sound_adapter *adpt; - - list_for_each_entry(adpt, &adpt_list, list) { - if (!adpt->registered) - goto adpt_alloc; - } - return -ENODEV; -adpt_alloc: - ret = snd_card_register(adpt->card); - if (ret < 0) { - release_adapter(adpt); - return ret; - } - adpt->registered = true; - return 0; -} - -/** - * audio_disconnect_channel - function to disconnect a channel - * @iface: pointer to interface instance - * @channel_id: channel index - * - * This frees allocated memory and removes the sound card from ALSA - * - * Returns 0 on success or error code otherwise. - */ -static int audio_disconnect_channel(struct most_interface *iface, - int channel_id) -{ - struct channel *channel; - struct sound_adapter *adpt = iface->priv; - - channel = get_channel(iface, channel_id); - if (!channel) - return -EINVAL; - - list_del(&channel->list); - - kfree(channel); - if (list_empty(&adpt->dev_list)) - release_adapter(adpt); - return 0; -} - -/** - * audio_rx_completion - completion handler for rx channels - * @mbo: pointer to buffer object that has completed - * - * This searches for the channel this MBO belongs to and copy the data from MBO - * to ring buffer - * - * Returns 0 on success or error code otherwise. - */ -static int audio_rx_completion(struct mbo *mbo) -{ - struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); - bool period_elapsed = false; - - if (!channel) - return -EINVAL; - if (channel->is_stream_running) - period_elapsed = copy_data(channel, mbo); - most_put_mbo(mbo); - if (period_elapsed) - snd_pcm_period_elapsed(channel->substream); - return 0; -} - -/** - * audio_tx_completion - completion handler for tx channels - * @iface: pointer to interface instance - * @channel_id: channel index/ID - * - * This searches the channel that belongs to this combination of interface - * pointer and channel ID and wakes a process sitting in the wait queue of - * this channel. - * - * Returns 0 on success or error code otherwise. - */ -static int audio_tx_completion(struct most_interface *iface, int channel_id) -{ - struct channel *channel = get_channel(iface, channel_id); - - if (!channel) - return -EINVAL; - - wake_up_interruptible(&channel->playback_waitq); - return 0; -} - -/** - * Initialization of the struct most_component - */ -static struct most_component comp = { - .mod = THIS_MODULE, - .name = DRIVER_NAME, - .probe_channel = audio_probe_channel, - .disconnect_channel = audio_disconnect_channel, - .rx_completion = audio_rx_completion, - .tx_completion = audio_tx_completion, - .cfg_complete = audio_create_sound_card, -}; - -static int __init audio_init(void) -{ - int ret; - - INIT_LIST_HEAD(&adpt_list); - - ret = most_register_component(&comp); - if (ret) { - pr_err("Failed to register %s\n", comp.name); - return ret; - } - ret = most_register_configfs_subsys(&comp); - if (ret) { - pr_err("Failed to register %s configfs subsys\n", comp.name); - most_deregister_component(&comp); - } - return ret; -} - -static void __exit audio_exit(void) -{ - most_deregister_configfs_subsys(&comp); - most_deregister_component(&comp); -} - -module_init(audio_init); -module_exit(audio_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Christian Gromm "); -MODULE_DESCRIPTION("Sound Component Module for Mostcore"); -- 2.7.4 From bokeefe at alum.wpi.edu Fri Nov 6 15:10:24 2020 From: bokeefe at alum.wpi.edu (Brian O'Keefe) Date: Fri, 6 Nov 2020 10:10:24 -0500 Subject: [PATCH] staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids In-Reply-To: <20201106101240.GA2770702@kroah.com> References: <20201106101240.GA2770702@kroah.com> Message-ID: On Fri, Nov 6, 2020 at 5:11 AM Greg Kroah-Hartman wrote: > > On Thu, Oct 29, 2020 at 09:52:16AM -0400, Brian O'Keefe wrote: > > Add 024c:0627 to the list of SDIO device-ids, based on hardware found in > > the wild. This hardware exists on at least some Acer SW1-011 tablets. > > > > Signed-off-by: Brian O'Keefe > > Reviewed-by: Hans de Goede > > --- > > drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > index 5b1392deb0a7..7256d55fcc1b 100644 > > --- a/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > +++ b/drivers/staging/rtl8723bs/os_dep/sdio_intf.c > > @@ -21,6 +21,7 @@ static const struct sdio_device_id sdio_ids[] = > > { SDIO_DEVICE(0x024c, 0x0525), }, > > { SDIO_DEVICE(0x024c, 0x0623), }, > > { SDIO_DEVICE(0x024c, 0x0626), }, > > + { SDIO_DEVICE(0x024c, 0x0627), }, > > { SDIO_DEVICE(0x024c, 0xb723), }, > > { /* end: all zeroes */ }, > > }; > > -- > > 2.25.1 > > All of the tabs are gone in your email and it's only spaces, making this > patch impossible to apply :( > > Can you fix up your email client and resend this and keep Hans's > Reviewed-by on it? > > thanks, > > greg k-h Sure thing. Sorry about that; I figured out how to get it to send properly this time. A corrected patch is on its way. From melissaann9298 at gmail.com Sat Nov 7 00:08:04 2020 From: melissaann9298 at gmail.com (Melissa Brown) Date: Sat, 7 Nov 2020 00:08:04 -0000 Subject: hi Message-ID: <20201107000809.E434687536@hemlock.osuosl.org> How are you doing today?Did you receive my message?Please let me know as soon as possible. Tony From digetx at gmail.com Sun Nov 8 12:19:16 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Sun, 8 Nov 2020 15:19:16 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> Message-ID: <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> 05.11.2020 18:22, Dmitry Osipenko ?????: > 05.11.2020 12:45, Ulf Hansson ?????: > ... >> I need some more time to review this, but just a quick check found a >> few potential issues... > > Thank you for starting the review! I'm pretty sure it will take a couple > revisions until all the questions will be resolved :) > >> The "core-supply", that you specify as a regulator for each >> controller's device node, is not the way we describe power domains. >> Instead, it seems like you should register a power-domain provider >> (with the help of genpd) and implement the ->set_performance_state() >> callback for it. Each device node should then be hooked up to this >> power-domain, rather than to a "core-supply". For DT bindings, please >> have a look at Documentation/devicetree/bindings/power/power-domain.yaml >> and Documentation/devicetree/bindings/power/power_domain.txt. >> >> In regards to the "sync state" problem (preventing to change >> performance states until all consumers have been attached), this can >> then be managed by the genpd provider driver instead. > > I'll need to take a closer look at GENPD, thank you for the suggestion. > > Sounds like a software GENPD driver which manages clocks and voltages > could be a good idea, but it also could be an unnecessary > over-engineering. Let's see.. > Hello Ulf and all, I took a detailed look at the GENPD and tried to implement it. Here is what was found: 1. GENPD framework doesn't aggregate performance requests from the attached devices. This means that if deviceA requests performance state 10 and then deviceB requests state 3, then framework will set domain's state to 3 instead of 10. https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L376 2. GENPD framework has a sync() callback in the genpd.domain structure, but this callback isn't allowed to be used by the GENPD implementation. The GENPD framework always overrides that callback for its own needs. Hence GENPD doesn't allow to solve the bootstrapping state-synchronization problem in a nice way. https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L2606 3. Tegra doesn't have a dedicated hardware power-controller for the core domain, instead there is only an external voltage regulator. Hence we will need to create a phony device-tree node for the virtual power domain, which is probably a wrong thing to do. === Perhaps it should be possible to create some hacks to work around bullets 2 and 3 in order to achieve what we need for DVFS on Tegra, but bullet 1 isn't solvable without changing how the GENPD core works. Altogether, the GENPD in its current form is a wrong abstraction for a system-wide DVFS in a case where multiple devices share power domain and this domain is a voltage regulator. The regulator framework is the correct abstraction in this case for today. From info34 at foescoc.com Sun Nov 8 13:03:19 2020 From: info34 at foescoc.com (FOESCO) Date: Sun, 8 Nov 2020 14:03:19 +0100 Subject: =?Windows-1252?Q?Formaci=F3n_Bonificable_(=DAltimo_plazo_de_inscr?= =?Windows-1252?Q?ipci=F3n_2020)?= Message-ID: <59364081696402732313050@DESKTOP-MFVDD89> Buenos d?as Os informamos que se encuentra abierto el plazo de inscripci?n para la "?LTIMA CONVOCATORIA 2020" de Cursos Bonificables para empleados en activo y en ERTE. Los cursos son 100% Bonificables con cargo al Cr?dito de Formaci?n 2020, si vuestra empresa todav?a dispone de Cr?dito de Formaci?n 2020 esta es la ?ltima oportunidad para poder consumirlo. Dese?is que os mandemos la informaci?n? Quedamos a la espera de vuestra respuesta. Saludos cordiales. Alex Pons Director FOESCO. FOESCO Formaci?n Estatal Continua. Entidad Organizadora: B200592AA www.foesco.com e-mail: cursos at foesco.net Tel: 910 323 794 (Horario de 9h a 15h y de 17h a 20h de Lunes a Viernes) FOESCO ofrece formaci?n a empresas y trabajadores en activo a trav?s de cursos bonificados por la Fundaci?n Estatal para la Formaci?n en el Empleo (antiguo FORCEM) que gestiona las acciones formativas de FORMACI?N CONTINUA para trabajadores y se rige por la ley 30/2015 de 9 de Septiembre. Antes de imprimir este e-mail piense bien si es necesario hacerlo. Before printing this e-mail please think twice if you really need it. FOESCO Tfno: 910 382 880 Email: cursos at foesco.com. La informaci?n transmitida en este mensaje est? dirigida solamente a las personas o entidades que figuran en el encabezamiento y contiene informaci?n confidencial, por lo que, si usted lo recibiera por error, por favor destr?yalo sin copiarlo, usarlo ni distribuirlo, comunic?ndolo inmediatamente al emisor del mensaje. De conformidad con lo dispuesto en el Reglamento Europeo del 2016/679, del 27 de Abril de 2016, FOESCO le informa que los datos por usted suministrados ser?n tratados con las medidas de seguridad conformes a la normativa vigente que se requiere. Dichos datos ser?n empleados con fines de gesti?n. Para el ejercicio de sus derechos de transparencia, informaci?n, acceso, rectificaci?n, supresi?n o derecho al olvido, limitaci?n del tratamiento , portabilidad de datos y oposici?n de sus datos de car?cter personal deber? dirigirse a la direcci?n del Responsable del tratamiento a C/ LAGUNA DEL MARQUESADO N?10, 28021, MADRID, "PULSANDO AQUI" y "ENVIAR" o a traves de la direcci?n de correo electr?nico: bajas at foesco.com From viresh.kumar at linaro.org Mon Nov 9 04:43:54 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 10:13:54 +0530 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> Message-ID: <20201109044354.ljd5pomhob6b7u5v@vireshk-i7> On 08-11-20, 15:19, Dmitry Osipenko wrote: > I took a detailed look at the GENPD and tried to implement it. Here is > what was found: > > 1. GENPD framework doesn't aggregate performance requests from the > attached devices. This means that if deviceA requests performance state > 10 and then deviceB requests state 3, then framework will set domain's > state to 3 instead of 10. It does. Look at _genpd_reeval_performance_state(). -- viresh From digetx at gmail.com Mon Nov 9 04:47:48 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 9 Nov 2020 07:47:48 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201109044354.ljd5pomhob6b7u5v@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <20201109044354.ljd5pomhob6b7u5v@vireshk-i7> Message-ID: <713b319e-bb7b-4743-59f0-b9892c3da92d@gmail.com> 09.11.2020 07:43, Viresh Kumar ?????: > On 08-11-20, 15:19, Dmitry Osipenko wrote: >> I took a detailed look at the GENPD and tried to implement it. Here is >> what was found: >> >> 1. GENPD framework doesn't aggregate performance requests from the >> attached devices. This means that if deviceA requests performance state >> 10 and then deviceB requests state 3, then framework will set domain's >> state to 3 instead of 10. > > It does. Look at _genpd_reeval_performance_state(). > Thanks, I probably had a bug in the quick prototype and then overlooked that function. From viresh.kumar at linaro.org Mon Nov 9 05:00:10 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 10:30:10 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> Message-ID: <20201109050010.g47zojh6wafvwqva@vireshk-i7> On 06-11-20, 21:41, Frank Lee wrote: > On Fri, Nov 6, 2020 at 9:18 PM Dmitry Osipenko wrote: > > > > 06.11.2020 09:15, Viresh Kumar ?????: > > > Setting regulators for count as 0 doesn't sound good to me. > > > > > > But, I understand that you don't want to have that if (have_regulator) > > > check, and it is a fair request. What I will instead do is, allow all > > > dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP > > > table and fail silently. And so you won't be required to have this > > > unwanted check. But you will be required to save the pointer returned > > > back by dev_pm_opp_set_regulators(), which is the right thing to do > > > anyways. > > > > Perhaps even a better variant could be to add a devm versions of the OPP > > API functions, then drivers won't need to care about storing the > > opp_table pointer if it's unused by drivers. > > I think so. The consumer may not be so concerned about the status of > these OPP tables. > If the driver needs to manage the release, it needs to add a pointer > to their driver global structure. > > Maybe it's worth having these devm interfaces for opp. Sure if there are enough users of this, I am all for it. I was fine with the patches you sent, just that there were not a lot of users of it and so I pushed them back. If we find that we have more users of it now, we can surely get that back. -- viresh From digetx at gmail.com Mon Nov 9 05:08:58 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 9 Nov 2020 08:08:58 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201109050010.g47zojh6wafvwqva@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> Message-ID: 09.11.2020 08:00, Viresh Kumar ?????: > On 06-11-20, 21:41, Frank Lee wrote: >> On Fri, Nov 6, 2020 at 9:18 PM Dmitry Osipenko wrote: >>> >>> 06.11.2020 09:15, Viresh Kumar ?????: >>>> Setting regulators for count as 0 doesn't sound good to me. >>>> >>>> But, I understand that you don't want to have that if (have_regulator) >>>> check, and it is a fair request. What I will instead do is, allow all >>>> dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP >>>> table and fail silently. And so you won't be required to have this >>>> unwanted check. But you will be required to save the pointer returned >>>> back by dev_pm_opp_set_regulators(), which is the right thing to do >>>> anyways. >>> >>> Perhaps even a better variant could be to add a devm versions of the OPP >>> API functions, then drivers won't need to care about storing the >>> opp_table pointer if it's unused by drivers. >> >> I think so. The consumer may not be so concerned about the status of >> these OPP tables. >> If the driver needs to manage the release, it needs to add a pointer >> to their driver global structure. >> >> Maybe it's worth having these devm interfaces for opp. > > Sure if there are enough users of this, I am all for it. I was fine > with the patches you sent, just that there were not a lot of users of > it and so I pushed them back. If we find that we have more users of it > now, we can surely get that back. > There was already attempt to add the devm? Could you please give me a link to the patches? I already prepared a patch which adds the devm helpers. It helps to keep code cleaner and readable. From viresh.kumar at linaro.org Mon Nov 9 05:10:14 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 10:40:14 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> Message-ID: <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> On 09-11-20, 08:08, Dmitry Osipenko wrote: > 09.11.2020 08:00, Viresh Kumar ?????: > > On 06-11-20, 21:41, Frank Lee wrote: > >> On Fri, Nov 6, 2020 at 9:18 PM Dmitry Osipenko wrote: > >>> > >>> 06.11.2020 09:15, Viresh Kumar ?????: > >>>> Setting regulators for count as 0 doesn't sound good to me. > >>>> > >>>> But, I understand that you don't want to have that if (have_regulator) > >>>> check, and it is a fair request. What I will instead do is, allow all > >>>> dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP > >>>> table and fail silently. And so you won't be required to have this > >>>> unwanted check. But you will be required to save the pointer returned > >>>> back by dev_pm_opp_set_regulators(), which is the right thing to do > >>>> anyways. > >>> > >>> Perhaps even a better variant could be to add a devm versions of the OPP > >>> API functions, then drivers won't need to care about storing the > >>> opp_table pointer if it's unused by drivers. > >> > >> I think so. The consumer may not be so concerned about the status of > >> these OPP tables. > >> If the driver needs to manage the release, it needs to add a pointer > >> to their driver global structure. > >> > >> Maybe it's worth having these devm interfaces for opp. > > > > Sure if there are enough users of this, I am all for it. I was fine > > with the patches you sent, just that there were not a lot of users of > > it and so I pushed them back. If we find that we have more users of it > > now, we can surely get that back. > > > > There was already attempt to add the devm? Could you please give me a > link to the patches? > > I already prepared a patch which adds the devm helpers. It helps to keep > code cleaner and readable. https://lore.kernel.org/lkml/20201012135517.19468-1-frank at allwinnertech.com/ -- viresh From digetx at gmail.com Mon Nov 9 05:10:16 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 9 Nov 2020 08:10:16 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <713b319e-bb7b-4743-59f0-b9892c3da92d@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <20201109044354.ljd5pomhob6b7u5v@vireshk-i7> <713b319e-bb7b-4743-59f0-b9892c3da92d@gmail.com> Message-ID: 09.11.2020 07:47, Dmitry Osipenko ?????: > 09.11.2020 07:43, Viresh Kumar ?????: >> On 08-11-20, 15:19, Dmitry Osipenko wrote: >>> I took a detailed look at the GENPD and tried to implement it. Here is >>> what was found: >>> >>> 1. GENPD framework doesn't aggregate performance requests from the >>> attached devices. This means that if deviceA requests performance state >>> 10 and then deviceB requests state 3, then framework will set domain's >>> state to 3 instead of 10. >> >> It does. Look at _genpd_reeval_performance_state(). >> > > Thanks, I probably had a bug in the quick prototype and then overlooked > that function. > If a non-hardware device-tree node is okay to have for the domain, then I can try again. What I also haven't mentioned is that GENPD adds some extra complexity to some drivers (3d, video decoder) because we will need to handle both new GENPD and legacy Tegra specific pre-genpd era domains. I'm also not exactly sure how the topology of domains should look like because Tegra has a power-controller (PMC) which manages power rail of a few hardware units. Perhaps it should be device -> PMC domain -> CORE domain but not exactly sure for now. From viresh.kumar at linaro.org Mon Nov 9 05:12:02 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 10:42:02 +0530 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <20201109044354.ljd5pomhob6b7u5v@vireshk-i7> <713b319e-bb7b-4743-59f0-b9892c3da92d@gmail.com> Message-ID: <20201109051202.e4lkosy6kk334akq@vireshk-i7> On 09-11-20, 08:10, Dmitry Osipenko wrote: > 09.11.2020 07:47, Dmitry Osipenko ?????: > > 09.11.2020 07:43, Viresh Kumar ?????: > >> On 08-11-20, 15:19, Dmitry Osipenko wrote: > >>> I took a detailed look at the GENPD and tried to implement it. Here is > >>> what was found: > >>> > >>> 1. GENPD framework doesn't aggregate performance requests from the > >>> attached devices. This means that if deviceA requests performance state > >>> 10 and then deviceB requests state 3, then framework will set domain's > >>> state to 3 instead of 10. > >> > >> It does. Look at _genpd_reeval_performance_state(). > >> > > > > Thanks, I probably had a bug in the quick prototype and then overlooked > > that function. > > > > If a non-hardware device-tree node is okay to have for the domain, then > I can try again. > > What I also haven't mentioned is that GENPD adds some extra complexity > to some drivers (3d, video decoder) because we will need to handle both > new GENPD and legacy Tegra specific pre-genpd era domains. > > I'm also not exactly sure how the topology of domains should look like > because Tegra has a power-controller (PMC) which manages power rail of a > few hardware units. Perhaps it should be > > device -> PMC domain -> CORE domain > > but not exactly sure for now. I am also confused on if it should be a domain or regulator, but that is for Ulf to tell :) -- viresh From digetx at gmail.com Mon Nov 9 05:19:32 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 9 Nov 2020 08:19:32 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> Message-ID: <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> 09.11.2020 08:10, Viresh Kumar ?????: > On 09-11-20, 08:08, Dmitry Osipenko wrote: >> 09.11.2020 08:00, Viresh Kumar ?????: >>> On 06-11-20, 21:41, Frank Lee wrote: >>>> On Fri, Nov 6, 2020 at 9:18 PM Dmitry Osipenko wrote: >>>>> >>>>> 06.11.2020 09:15, Viresh Kumar ?????: >>>>>> Setting regulators for count as 0 doesn't sound good to me. >>>>>> >>>>>> But, I understand that you don't want to have that if (have_regulator) >>>>>> check, and it is a fair request. What I will instead do is, allow all >>>>>> dev_pm_opp_put*() API to start accepting a NULL pointer for the OPP >>>>>> table and fail silently. And so you won't be required to have this >>>>>> unwanted check. But you will be required to save the pointer returned >>>>>> back by dev_pm_opp_set_regulators(), which is the right thing to do >>>>>> anyways. >>>>> >>>>> Perhaps even a better variant could be to add a devm versions of the OPP >>>>> API functions, then drivers won't need to care about storing the >>>>> opp_table pointer if it's unused by drivers. >>>> >>>> I think so. The consumer may not be so concerned about the status of >>>> these OPP tables. >>>> If the driver needs to manage the release, it needs to add a pointer >>>> to their driver global structure. >>>> >>>> Maybe it's worth having these devm interfaces for opp. >>> >>> Sure if there are enough users of this, I am all for it. I was fine >>> with the patches you sent, just that there were not a lot of users of >>> it and so I pushed them back. If we find that we have more users of it >>> now, we can surely get that back. >>> >> >> There was already attempt to add the devm? Could you please give me a >> link to the patches? >> >> I already prepared a patch which adds the devm helpers. It helps to keep >> code cleaner and readable. > > https://lore.kernel.org/lkml/20201012135517.19468-1-frank at allwinnertech.com/ > Thanks, I made it in a different way by simply adding helpers to the pm_opp.h which use devm_add_action_or_reset(). This doesn't require to add new kernel symbols. static inline int devm_pm_opp_of_add_table(struct device *dev) { int err; err = dev_pm_opp_of_add_table(dev); if (err) return err; err = devm_add_action_or_reset(dev, (void*)dev_pm_opp_remove_table, dev); if (err) return err; return 0; } From viresh.kumar at linaro.org Mon Nov 9 05:35:46 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 11:05:46 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> References: <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> Message-ID: <20201109053546.xupmmsx5qccn46tr@vireshk-i7> On 09-11-20, 08:19, Dmitry Osipenko wrote: > Thanks, I made it in a different way by simply adding helpers to the > pm_opp.h which use devm_add_action_or_reset(). This doesn't require to > add new kernel symbols. I will prefer to add it in core.c itself, and yes devm_add_action_or_reset() looks better. But I am still not sure for which helpers do we need the devm_*() variants, as this is only useful for non-CPU devices. But if we have users that we can add right now, why not. > static inline int devm_pm_opp_of_add_table(struct device *dev) > { > int err; > > err = dev_pm_opp_of_add_table(dev); > if (err) > return err; > > err = devm_add_action_or_reset(dev, (void*)dev_pm_opp_remove_table, > dev); > if (err) > return err; > > return 0; > } -- viresh From digetx at gmail.com Mon Nov 9 05:44:22 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 9 Nov 2020 08:44:22 +0300 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201109053546.xupmmsx5qccn46tr@vireshk-i7> References: <20201104234427.26477-18-digetx@gmail.com> <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> <20201109053546.xupmmsx5qccn46tr@vireshk-i7> Message-ID: <33a7ad95-a8cf-7b88-0f78-09086c1a4adf@gmail.com> 09.11.2020 08:35, Viresh Kumar ?????: > On 09-11-20, 08:19, Dmitry Osipenko wrote: >> Thanks, I made it in a different way by simply adding helpers to the >> pm_opp.h which use devm_add_action_or_reset(). This doesn't require to >> add new kernel symbols. > > I will prefer to add it in core.c itself, and yes > devm_add_action_or_reset() looks better. But I am still not sure for > which helpers do we need the devm_*() variants, as this is only useful > for non-CPU devices. But if we have users that we can add right now, > why not. All current non-CPU drivers (devfreq, mmc, memory, etc) can benefit from it. For Tegra drivers we need these variants: devm_pm_opp_set_supported_hw() devm_pm_opp_set_regulators() [if we won't use GENPD] devm_pm_opp_set_clkname() devm_pm_opp_of_add_table() From viresh.kumar at linaro.org Mon Nov 9 05:53:20 2020 From: viresh.kumar at linaro.org (Viresh Kumar) Date: Mon, 9 Nov 2020 11:23:20 +0530 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <33a7ad95-a8cf-7b88-0f78-09086c1a4adf@gmail.com> References: <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> <20201109053546.xupmmsx5qccn46tr@vireshk-i7> <33a7ad95-a8cf-7b88-0f78-09086c1a4adf@gmail.com> Message-ID: <20201109055320.5y5gf2whwast2mi4@vireshk-i7> On 09-11-20, 08:44, Dmitry Osipenko wrote: > 09.11.2020 08:35, Viresh Kumar ?????: > > On 09-11-20, 08:19, Dmitry Osipenko wrote: > >> Thanks, I made it in a different way by simply adding helpers to the > >> pm_opp.h which use devm_add_action_or_reset(). This doesn't require to > >> add new kernel symbols. > > > > I will prefer to add it in core.c itself, and yes > > devm_add_action_or_reset() looks better. But I am still not sure for > > which helpers do we need the devm_*() variants, as this is only useful > > for non-CPU devices. But if we have users that we can add right now, > > why not. > > All current non-CPU drivers (devfreq, mmc, memory, etc) can benefit from it. > > For Tegra drivers we need these variants: > > devm_pm_opp_set_supported_hw() > devm_pm_opp_set_regulators() [if we won't use GENPD] > devm_pm_opp_set_clkname() > devm_pm_opp_of_add_table() I tried to look earlier for the stuff already merged in and didn't find a lot of stuff where the devm_* could be used, maybe I missed some of it. Frank, would you like to refresh your series based on suggestions from Dmitry and make other drivers adapt to the new APIs ? -- viresh From maxime at cerno.tech Mon Nov 9 09:43:03 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Mon, 9 Nov 2020 10:43:03 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201106160737.GA31913@lst.de> References: <20201106151411.321743-1-maxime@cerno.tech> <20201106160737.GA31913@lst.de> Message-ID: <20201109094303.llqsxqoxjagiqa55@gilmour.lan> Hi Christoph, Chen-Yu, Hans, On Fri, Nov 06, 2020 at 05:07:37PM +0100, Christoph Hellwig wrote: > Thanks, > > this looks good to me: > > Reviewed-by: Christoph Hellwig > > Can you include this patch at the end of your series to that it gets > picked up with the other patches? I guess the easiest to avoid bisection issues would be to merge all this through drm-misc, would that work for you? Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From hch at lst.de Mon Nov 9 09:47:09 2020 From: hch at lst.de (Christoph Hellwig) Date: Mon, 9 Nov 2020 10:47:09 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201109094303.llqsxqoxjagiqa55@gilmour.lan> References: <20201106151411.321743-1-maxime@cerno.tech> <20201106160737.GA31913@lst.de> <20201109094303.llqsxqoxjagiqa55@gilmour.lan> Message-ID: <20201109094709.GA31714@lst.de> On Mon, Nov 09, 2020 at 10:43:03AM +0100, Maxime Ripard wrote: > Hi Christoph, Chen-Yu, Hans, > > On Fri, Nov 06, 2020 at 05:07:37PM +0100, Christoph Hellwig wrote: > > Thanks, > > > > this looks good to me: > > > > Reviewed-by: Christoph Hellwig > > > > Can you include this patch at the end of your series to that it gets > > picked up with the other patches? > > I guess the easiest to avoid bisection issues would be to merge all this > through drm-misc, would that work for you? Fine with me! From tiny.windzz at gmail.com Mon Nov 9 11:20:50 2020 From: tiny.windzz at gmail.com (Frank Lee) Date: Mon, 9 Nov 2020 19:20:50 +0800 Subject: [PATCH v1 17/30] mmc: sdhci-tegra: Support OPP and core voltage scaling In-Reply-To: <20201109055320.5y5gf2whwast2mi4@vireshk-i7> References: <6fa54ce6-d5ae-d04f-7c77-b62c148d92b7@gmail.com> <20201106061513.uyys7njcqcdlah67@vireshk-i7> <20201109050010.g47zojh6wafvwqva@vireshk-i7> <20201109051014.oa6bt4g3ctm2hnuy@vireshk-i7> <4476fed9-a356-b7f1-32ee-935343e23038@gmail.com> <20201109053546.xupmmsx5qccn46tr@vireshk-i7> <33a7ad95-a8cf-7b88-0f78-09086c1a4adf@gmail.com> <20201109055320.5y5gf2whwast2mi4@vireshk-i7> Message-ID: On Mon, Nov 9, 2020 at 1:53 PM Viresh Kumar wrote: > > On 09-11-20, 08:44, Dmitry Osipenko wrote: > > 09.11.2020 08:35, Viresh Kumar ?????: > > > On 09-11-20, 08:19, Dmitry Osipenko wrote: > > >> Thanks, I made it in a different way by simply adding helpers to the > > >> pm_opp.h which use devm_add_action_or_reset(). This doesn't require to > > >> add new kernel symbols. > > > > > > I will prefer to add it in core.c itself, and yes > > > devm_add_action_or_reset() looks better. But I am still not sure for > > > which helpers do we need the devm_*() variants, as this is only useful > > > for non-CPU devices. But if we have users that we can add right now, > > > why not. > > > > All current non-CPU drivers (devfreq, mmc, memory, etc) can benefit from it. > > > > For Tegra drivers we need these variants: > > > > devm_pm_opp_set_supported_hw() > > devm_pm_opp_set_regulators() [if we won't use GENPD] > > devm_pm_opp_set_clkname() > > devm_pm_opp_of_add_table() > > I tried to look earlier for the stuff already merged in and didn't > find a lot of stuff where the devm_* could be used, maybe I missed > some of it. > > Frank, would you like to refresh your series based on suggestions from > Dmitry and make other drivers adapt to the new APIs ? I am glad to do this.?? Yangtao From zhangqilong3 at huawei.com Mon Nov 9 13:13:45 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Mon, 9 Nov 2020 21:13:45 +0800 Subject: [PATCH 0/2] Fix reference counter leak in error banch Message-ID: <20201109131347.1725288-1-zhangqilong3@huawei.com> There are two reference counter leaks in greybus moduler refer to gb_pm_runtime_get_sync, and we fixed it. Zhang Qilong (2): staging: greybus: codecs: Fix reference counter leak in error handling greybus: audio: apbridgea: Fix reference counter leak in error handling drivers/staging/greybus/audio_apbridgea.c | 6 +++++- drivers/staging/greybus/audio_codec.c | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) -- 2.25.4 From zhangqilong3 at huawei.com Mon Nov 9 13:13:46 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Mon, 9 Nov 2020 21:13:46 +0800 Subject: [PATCH 1/2] staging: greybus: codecs: Fix reference counter leak in error handling In-Reply-To: <20201109131347.1725288-1-zhangqilong3@huawei.com> References: <20201109131347.1725288-1-zhangqilong3@huawei.com> Message-ID: <20201109131347.1725288-2-zhangqilong3@huawei.com> gb_pm_runtime_get_sync has increased the usage counter of the device here. Forgetting to call gb_pm_runtime_put_noidle will result in usage counter leak in the error branch of (gbcodec_hw_params and gbcodec_prepare). We fixed it by adding it. Fixes: c388ae7696992 ("greybus: audio: Update pm runtime support in dai_ops callback") Signed-off-by: Zhang Qilong --- drivers/staging/greybus/audio_codec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c index 17a39ed63769..b589cf6b1d03 100644 --- a/drivers/staging/greybus/audio_codec.c +++ b/drivers/staging/greybus/audio_codec.c @@ -471,6 +471,7 @@ static int gbcodec_hw_params(struct snd_pcm_substream *substream, if (ret) { dev_err_ratelimited(dai->dev, "%d: Error during set_config\n", ret); + gb_pm_runtime_put_noidle(bundle); mutex_unlock(&codec->lock); return ret; } @@ -545,6 +546,7 @@ static int gbcodec_prepare(struct snd_pcm_substream *substream, break; } if (ret) { + gb_pm_runtime_put_noidle(bundle); mutex_unlock(&codec->lock); dev_err_ratelimited(dai->dev, "set_data_size failed:%d\n", ret); return ret; -- 2.25.4 From zhangqilong3 at huawei.com Mon Nov 9 13:13:47 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Mon, 9 Nov 2020 21:13:47 +0800 Subject: [PATCH 2/2] greybus: audio: apbridgea: Fix reference counter leak in error handling In-Reply-To: <20201109131347.1725288-1-zhangqilong3@huawei.com> References: <20201109131347.1725288-1-zhangqilong3@huawei.com> Message-ID: <20201109131347.1725288-3-zhangqilong3@huawei.com> When gb_audio_apbridgea_register_cport failed, maybe: 1) gb_pm_runtime_get_sync failed, usage counter remained unchanged; 2) gb_hd_output failed, usage counter remained increased; In error state, there are two different states in usage cpounter. So, if gb_hd_output failed, we should call gb_pm_runtime_put_autosuspend ot decrease usage counter for balabce preventing reference leak. And we fixed it by add gb_pm_runtime_put_autosuspend when gb_hd_output failed. Fixes: 6ba7fad430d63 ("Add runtime pm support to audio protocol device class driver.") Signed-off-by: Zhang Qilong --- drivers/staging/greybus/audio_apbridgea.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio_apbridgea.c b/drivers/staging/greybus/audio_apbridgea.c index 26117e390deb..50545fd9756c 100644 --- a/drivers/staging/greybus/audio_apbridgea.c +++ b/drivers/staging/greybus/audio_apbridgea.c @@ -42,8 +42,12 @@ int gb_audio_apbridgea_register_cport(struct gb_connection *connection, if (ret) return ret; - return gb_hd_output(connection->hd, &req, sizeof(req), + ret = gb_hd_output(connection->hd, &req, sizeof(req), GB_APB_REQUEST_AUDIO_CONTROL, true); + if (ret) + gb_pm_runtime_put_autosuspend(connection->bundle); + + return ret; } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_register_cport); -- 2.25.4 From gregkh at linuxfoundation.org Mon Nov 9 15:07:44 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Mon, 9 Nov 2020 16:07:44 +0100 Subject: [PATCH] Fixed issues with alignment to open parenthesis. In-Reply-To: <20201012010838.GA1406@tabot> References: <20201012010838.GA1406@tabot> Message-ID: <20201109150744.GA1984969@kroah.com> On Mon, Oct 12, 2020 at 02:08:38AM +0100, Tabot Kevin wrote: > This patch fixes the following: > - Made sure alignment matched open parenthesis. > > Signed-off-by: Tabot Kevin > --- > drivers/staging/greybus/audio_module.c | 8 ++++---- > 1 file changed, 4 insertions(+), 4 deletions(-) > > diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c > index c52c4f3..a243d60 100644 > --- a/drivers/staging/greybus/audio_module.c > +++ b/drivers/staging/greybus/audio_module.c Please use scripts/get_maintainer.pl to know who to cc: on a patch. And look at other changes for this file, and copy the subject prefix for them: $ git log --oneline drivers/staging/greybus/audio_module.c | head 50a390ad1512 staging: greybus: fix warnings about endianness detected by sparse ac40b4d1e409 staging: greybus: audio: Maintain jack list within GB Audio module 8478c35a858c staging: greybus: Parenthesis alignment 863dbc52e7f0 staging: greybus: Remove redundant license text eb50fd3a22c7 staging: greybus: add SPDX identifiers to all greybus driver files 055fb9ce92d5 staging: greybus: audio: Ensure proper byte order 3282998c8010 staging: greybus: audio_module: remove redundant OOM message 49b9137a6002 staging: greybus: audio: remove redundant slot field d0af1bd5f6f4 staging: greybus: audio: Rename cport with intf_id 948c6227e76e staging: greybus: remove CONFIG_PM_RUNTIME from kernel_ver.h Can you fix that up and resend? thanks, greg k-h From lkp at intel.com Mon Nov 9 16:56:06 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 10 Nov 2020 00:56:06 +0800 Subject: [staging:staging-linus] BUILD SUCCESS aee9dccc5b64e878cf1b18207436e73f66d74157 Message-ID: <5fa974a6.rlaMmVyJoL6SNJH+%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-linus branch HEAD: aee9dccc5b64e878cf1b18207436e73f66d74157 staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids elapsed time: 720m configs tested: 127 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig arc nsim_700_defconfig powerpc holly_defconfig xtensa audio_kc705_defconfig sh se7343_defconfig arm colibri_pxa270_defconfig nds32 alldefconfig arm hisi_defconfig arm assabet_defconfig m68k m5272c3_defconfig arm pxa910_defconfig x86_64 allyesconfig openrisc simple_smp_defconfig xtensa cadence_csp_defconfig mips maltaaprp_defconfig mips cavium_octeon_defconfig m68k alldefconfig nios2 10m50_defconfig powerpc tqm8548_defconfig c6x evmc6474_defconfig sh rsk7201_defconfig nios2 3c120_defconfig powerpc mpc7448_hpc2_defconfig arm badge4_defconfig arm multi_v4t_defconfig h8300 defconfig arm collie_defconfig arc defconfig mips fuloong2e_defconfig sh microdev_defconfig arm mmp2_defconfig sh sh7757lcr_defconfig arm hackkit_defconfig powerpc linkstation_defconfig arm h5000_defconfig sh hp6xx_defconfig arm lpd270_defconfig um x86_64_defconfig mips rm200_defconfig powerpc bamboo_defconfig arm u300_defconfig arm omap2plus_defconfig mips ip27_defconfig powerpc mpc8560_ads_defconfig mips qi_lb60_defconfig powerpc mpc836x_mds_defconfig m68k m5307c3_defconfig arm rpc_defconfig c6x alldefconfig powerpc pmac32_defconfig arm imote2_defconfig arc vdk_hs38_defconfig arm pcm027_defconfig arm realview_defconfig mips rb532_defconfig mips nlm_xlr_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig x86_64 randconfig-a004-20201109 x86_64 randconfig-a002-20201109 x86_64 randconfig-a003-20201109 x86_64 randconfig-a005-20201109 x86_64 randconfig-a006-20201109 x86_64 randconfig-a001-20201109 i386 randconfig-a004-20201109 i386 randconfig-a006-20201109 i386 randconfig-a005-20201109 i386 randconfig-a001-20201109 i386 randconfig-a003-20201109 i386 randconfig-a002-20201109 i386 randconfig-a014-20201109 i386 randconfig-a015-20201109 i386 randconfig-a013-20201109 i386 randconfig-a016-20201109 i386 randconfig-a011-20201109 i386 randconfig-a012-20201109 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a012-20201109 x86_64 randconfig-a015-20201109 x86_64 randconfig-a013-20201109 x86_64 randconfig-a011-20201109 x86_64 randconfig-a014-20201109 x86_64 randconfig-a016-20201109 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From robh at kernel.org Mon Nov 9 18:57:25 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 12:57:25 -0600 Subject: [PATCH v1 01/30] dt-bindings: host1x: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-2-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-2-digetx@gmail.com> Message-ID: <20201109185725.GA1586511@bogus> On Thu, 05 Nov 2020 02:43:58 +0300, Dmitry Osipenko wrote: > Document new DVFS OPP table and voltage regulator properties of the > Host1x bus and devices sitting on the bus. > > Signed-off-by: Dmitry Osipenko > --- > .../display/tegra/nvidia,tegra20-host1x.txt | 56 +++++++++++++++++++ > 1 file changed, 56 insertions(+) > Reviewed-by: Rob Herring From robh at kernel.org Mon Nov 9 18:58:37 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 12:58:37 -0600 Subject: [PATCH v1 02/30] dt-bindings: mmc: tegra: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-3-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-3-digetx@gmail.com> Message-ID: <20201109185837.GA1588183@bogus> On Thu, 05 Nov 2020 02:43:59 +0300, Dmitry Osipenko wrote: > Document new DVFS OPP table and voltage regulator properties of the > SDHCI controller. > > Signed-off-by: Dmitry Osipenko > --- > .../devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > Reviewed-by: Rob Herring From robh at kernel.org Mon Nov 9 19:00:30 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 13:00:30 -0600 Subject: [PATCH v1 03/30] dt-bindings: pwm: tegra: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-4-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-4-digetx@gmail.com> Message-ID: <20201109190030.GA1590784@bogus> On Thu, 05 Nov 2020 02:44:00 +0300, Dmitry Osipenko wrote: > Document new DVFS OPP table and voltage regulator properties of the > PWM controller. > > Signed-off-by: Dmitry Osipenko > --- > .../devicetree/bindings/pwm/nvidia,tegra20-pwm.txt | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > Reviewed-by: Rob Herring From robh at kernel.org Mon Nov 9 19:01:29 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 13:01:29 -0600 Subject: [PATCH v1 04/30] media: dt: bindings: tegra-vde: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-5-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-5-digetx@gmail.com> Message-ID: <20201109190129.GA1592208@bogus> On Thu, 05 Nov 2020 02:44:01 +0300, Dmitry Osipenko wrote: > Document new DVFS OPP table and voltage regulator properties of the > video decoder engine. > > Signed-off-by: Dmitry Osipenko > --- > .../devicetree/bindings/media/nvidia,tegra-vde.txt | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > Reviewed-by: Rob Herring From robh at kernel.org Mon Nov 9 19:01:41 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 13:01:41 -0600 Subject: [PATCH v1 05/30] dt-binding: usb: ci-hdrc-usb2: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-6-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-6-digetx@gmail.com> Message-ID: <20201109190141.GA1592558@bogus> On Thu, 05 Nov 2020 02:44:02 +0300, Dmitry Osipenko wrote: > Document new OPP table and NVIDIA Tegra-specific voltage regulator > properties. > > Signed-off-by: Dmitry Osipenko > --- > Documentation/devicetree/bindings/usb/ci-hdrc-usb2.txt | 4 ++++ > 1 file changed, 4 insertions(+) > Reviewed-by: Rob Herring From robh at kernel.org Mon Nov 9 19:01:51 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 9 Nov 2020 13:01:51 -0600 Subject: [PATCH v1 06/30] dt-bindings: usb: tegra-ehci: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-7-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-7-digetx@gmail.com> Message-ID: <20201109190151.GA1592922@bogus> On Thu, 05 Nov 2020 02:44:03 +0300, Dmitry Osipenko wrote: > Document new DVFS OPP table and voltage regulator properties of the > Tegra EHCI controller. > > Signed-off-by: Dmitry Osipenko > --- > Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt | 2 ++ > 1 file changed, 2 insertions(+) > Reviewed-by: Rob Herring From eduard.vintila47 at gmail.com Mon Nov 9 20:20:16 2020 From: eduard.vintila47 at gmail.com (Eduard Vintila) Date: Mon, 9 Nov 2020 22:20:16 +0200 Subject: [PATCH] staging: rtl8192e: Braces should be used on all arms of statement Message-ID: <20201109202016.79329-1-eduard.vintila47@gmail.com> Fixed a coding style issue by adding braces on all arms of an "if" statement. Signed-off-by: Eduard Vintila --- drivers/staging/rtl8192e/rtl819x_HTProc.c | 27 ++++++++++++----------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c index 8abc921ecb3e..9377e48c3f32 100644 --- a/drivers/staging/rtl8192e/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c @@ -177,33 +177,34 @@ static void HTIOTPeerDetermine(struct rtllib_device *ieee) pHTInfo->IOTPeer = HT_IOT_PEER_REALTEK_92SE; if (net->bssht.RT2RT_HT_Mode & RT_HT_CAP_USE_SOFTAP) pHTInfo->IOTPeer = HT_IOT_PEER_92U_SOFTAP; - } else if (net->broadcom_cap_exist) + } else if (net->broadcom_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; - else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || + } else if (!memcmp(net->bssid, UNKNOWN_BORADCOM, 3) || !memcmp(net->bssid, LINKSYSWRT330_LINKSYSWRT300_BROADCOM, 3) || - !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) + !memcmp(net->bssid, LINKSYSWRT350_LINKSYSWRT150_BROADCOM, 3)) { pHTInfo->IOTPeer = HT_IOT_PEER_BROADCOM; - else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || + } else if ((memcmp(net->bssid, BELKINF5D8233V1_RALINK, 3) == 0) || (memcmp(net->bssid, BELKINF5D82334V3_RALINK, 3) == 0) || (memcmp(net->bssid, PCI_RALINK, 3) == 0) || (memcmp(net->bssid, EDIMAX_RALINK, 3) == 0) || (memcmp(net->bssid, AIRLINK_RALINK, 3) == 0) || - net->ralink_cap_exist) + net->ralink_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_RALINK; - else if ((net->atheros_cap_exist) || + } else if ((net->atheros_cap_exist) || (memcmp(net->bssid, DLINK_ATHEROS_1, 3) == 0) || - (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) + (memcmp(net->bssid, DLINK_ATHEROS_2, 3) == 0)) { pHTInfo->IOTPeer = HT_IOT_PEER_ATHEROS; - else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) || - net->cisco_cap_exist) + } else if ((memcmp(net->bssid, CISCO_BROADCOM, 3) == 0) || + net->cisco_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_CISCO; - else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || - net->marvell_cap_exist) + } else if ((memcmp(net->bssid, LINKSYS_MARVELL_4400N, 3) == 0) || + net->marvell_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_MARVELL; - else if (net->airgo_cap_exist) + } else if (net->airgo_cap_exist) { pHTInfo->IOTPeer = HT_IOT_PEER_AIRGO; - else + } else { pHTInfo->IOTPeer = HT_IOT_PEER_UNKNOWN; + } netdev_dbg(ieee->dev, "IOTPEER: %x\n", pHTInfo->IOTPeer); } -- 2.29.2 From lkp at intel.com Mon Nov 9 21:54:42 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 10 Nov 2020 05:54:42 +0800 Subject: [staging:staging-testing] BUILD SUCCESS f4acd33c446b2ba97f1552a4da90050109d01ca7 Message-ID: <5fa9baa2.9tSbMWO8+rFfv3vo%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: f4acd33c446b2ba97f1552a4da90050109d01ca7 staging: rtl8723bs: replace ieee80211_back_actioncode elapsed time: 1017m configs tested: 108 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig powerpc storcenter_defconfig ia64 zx1_defconfig sh migor_defconfig powerpc sam440ep_defconfig powerpc pseries_defconfig m68k amcore_defconfig arm s5pv210_defconfig xtensa audio_kc705_defconfig m68k hp300_defconfig sh se7206_defconfig arm ep93xx_defconfig arc nsimosci_defconfig mips mtx1_defconfig arm mvebu_v7_defconfig arm exynos_defconfig arc defconfig mips fuloong2e_defconfig sh microdev_defconfig arm mmp2_defconfig arm collie_defconfig sh sh7757lcr_defconfig m68k m5307c3_defconfig arm rpc_defconfig m68k m5272c3_defconfig c6x alldefconfig powerpc pmac32_defconfig arm imote2_defconfig parisc alldefconfig arm shmobile_defconfig arm milbeaut_m10v_defconfig powerpc tqm8540_defconfig powerpc skiroot_defconfig arm shannon_defconfig nds32 defconfig arm corgi_defconfig arm gemini_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a004-20201109 i386 randconfig-a006-20201109 i386 randconfig-a005-20201109 i386 randconfig-a001-20201109 i386 randconfig-a003-20201109 i386 randconfig-a002-20201109 i386 randconfig-a014-20201109 i386 randconfig-a015-20201109 i386 randconfig-a013-20201109 i386 randconfig-a016-20201109 i386 randconfig-a011-20201109 i386 randconfig-a012-20201109 x86_64 randconfig-a003-20201110 x86_64 randconfig-a005-20201110 x86_64 randconfig-a004-20201110 x86_64 randconfig-a002-20201110 x86_64 randconfig-a006-20201110 x86_64 randconfig-a001-20201110 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a012-20201109 x86_64 randconfig-a015-20201109 x86_64 randconfig-a013-20201109 x86_64 randconfig-a011-20201109 x86_64 randconfig-a014-20201109 x86_64 randconfig-a016-20201109 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From tabot.kevin at gmail.com Tue Nov 10 00:44:00 2020 From: tabot.kevin at gmail.com (Tabot Kevin) Date: Tue, 10 Nov 2020 01:44:00 +0100 Subject: [PATCH] staging: greybus: Fixed issues with alignment to open parenthesis. Message-ID: <20201110004356.GA1803@tabot> This patch fixes the following: - Made sure alignment matched open parenthesis. Signed-off-by: Tabot Kevin --- drivers/staging/greybus/audio_module.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c index c52c4f3..a243d60 100644 --- a/drivers/staging/greybus/audio_module.c +++ b/drivers/staging/greybus/audio_module.c @@ -175,8 +175,8 @@ static int gbaudio_codec_request_handler(struct gb_operation *op) } static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) + struct greybus_descriptor_cport *cport_desc, + struct gb_bundle *bundle) { struct gb_connection *connection; @@ -199,8 +199,8 @@ static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule, } static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) + struct greybus_descriptor_cport *cport_desc, + struct gb_bundle *bundle) { struct gb_connection *connection; struct gbaudio_data_connection *dai; -- 2.7.4 From tglx at linutronix.de Tue Nov 10 01:13:56 2020 From: tglx at linutronix.de (Thomas Gleixner) Date: Tue, 10 Nov 2020 02:13:56 +0100 Subject: [PATCH RFC PKS/PMEM 05/58] kmap: Introduce k[un]map_thread In-Reply-To: <20201009195033.3208459-6-ira.weiny@intel.com> References: <20201009195033.3208459-1-ira.weiny@intel.com> <20201009195033.3208459-6-ira.weiny@intel.com> Message-ID: <87h7pyhv3f.fsf@nanos.tec.linutronix.de> Ira, On Fri, Oct 09 2020 at 12:49, ira weiny wrote: > From: Ira Weiny > > To correctly support the semantics of kmap() with Kernel protection keys > (PKS), kmap() may be required to set the protections on multiple > processors (globally). Enabling PKS globally can be very expensive > depending on the requested operation. Furthermore, enabling a domain > globally reduces the protection afforded by PKS. > > Most kmap() (Aprox 209 of 229) callers use the map within a single thread and > have no need for the protection domain to be enabled globally. However, the > remaining callers do not follow this pattern and, as best I can tell, expect > the mapping to be 'global' and available to any thread who may access the > mapping.[1] > > We don't anticipate global mappings to pmem, however in general there is a > danger in changing the semantics of kmap(). Effectively, this would cause an > unresolved page fault with little to no information about why the failure > occurred. > > To resolve this a number of options were considered. > > 1) Attempt to change all the thread local kmap() calls to kmap_atomic()[2] > 2) Introduce a flags parameter to kmap() to indicate if the mapping should be > global or not > 3) Change ~20 call sites to 'kmap_global()' to indicate that they require a > global enablement of the pages. > 4) Change ~209 call sites to 'kmap_thread()' to indicate that the mapping is to > be used within that thread of execution only > > Option 1 is simply not feasible. Option 2 would require all of the call sites > of kmap() to change. Option 3 seems like a good minimal change but there is a > danger that new code may miss the semantic change of kmap() and not get the > behavior the developer intended. Therefore, #4 was chosen. There is Option #5: Convert the thread local kmap() invocations to the proposed kmap_local() interface which is coming along [1]. That solves a couple of issues: 1) It relieves the current kmap_atomic() usage sites from the implict pagefault/preempt disable semantics which apply even when CONFIG_HIGHMEM is disabled. kmap_local() still can be invoked from atomic context. 2) Due to #1 it allows to replace the conditional usage of kmap() and kmap_atomic() for purely thread local mappings. 3) It puts the burden on the HIGHMEM inflicted systems 4) It is actually more efficient for most of the pure thread local use cases on HIGHMEM inflicted systems because it avoids the overhead of the global lock and the potential kmap slot exhaustion. A potential preemption will be more expensive, but that's not really the case we want to optimize for. 5) It solves the RT issue vs. kmap_atomic() So instead of creating yet another variety of kmap() which is just scratching the particular PKRS itch, can we please consolidate all of that on the wider reaching kmap_local() approach? Thanks, tglx [1] https://lore.kernel.org/lkml/20201103092712.714480842 at linutronix.de/ From ross.schm.dev at gmail.com Tue Nov 10 04:09:59 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:09:59 -0600 Subject: [PATCH 01/10] staging: rtl8723bs: clean up line spacing Message-ID: <20201110041008.15847-1-ross.schm.dev@gmail.com> Add or remove lines to fix coding style issues and clear checkpatch. WARNING: Missing a blank line after declarations CHECK: Please use a blank line after function/struct/union/enum declarations CHECK: Please don't use multiple blank lines Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_security.c | 29 ++++--------------- drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 7 +---- .../staging/rtl8723bs/core/rtw_wlan_util.c | 12 +++++++- drivers/staging/rtl8723bs/core/rtw_xmit.c | 3 ++ 4 files changed, 20 insertions(+), 31 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 81c15895f646..894e7beae96f 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -1008,7 +1008,6 @@ static void shift_row(u8 *in, u8 *out) out[15] = in[11]; } - static void mix_column(u8 *in, u8 *out) { sint i; @@ -1098,7 +1097,6 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) } } - /************************************************/ /* construct_mic_iv() */ /* Builds the MIC IV from header fields and PN */ @@ -1145,7 +1143,6 @@ static void construct_mic_iv( mic_iv[15] = (unsigned char) (payload_length % 256); } - /************************************************/ /* construct_mic_header1() */ /* Builds the first MIC header block from */ @@ -1183,7 +1180,6 @@ static void construct_mic_header1( mic_header1[15] = mpdu[15]; } - /************************************************/ /* construct_mic_header2() */ /* Builds the last MIC header block from */ @@ -1211,7 +1207,6 @@ static void construct_mic_header2( mic_header2[6] = 0x00; mic_header2[7] = 0x00; /* mpdu[23]; */ - if (!qc_exists && a4_exists) { for (i = 0; i < 6; i++) mic_header2[8+i] = mpdu[24+i]; /* A4 */ @@ -1277,7 +1272,6 @@ static void construct_ctr_preload( ctr_preload[15] = (unsigned char) (c % 256); } - /************************************/ /* bitwise_xor() */ /* A 128 bit, bitwise exclusive or */ @@ -1291,7 +1285,6 @@ static void bitwise_xor(u8 *ina, u8 *inb, u8 *out) } } - static sint aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen) { @@ -1314,7 +1307,6 @@ static sint aes_cipher(u8 *key, uint hdrlen, frsubtype = frsubtype>>4; - memset((void *)mic_iv, 0, 16); memset((void *)mic_header1, 0, 16); memset((void *)mic_header2, 0, 16); @@ -1377,7 +1369,6 @@ static sint aes_cipher(u8 *key, uint hdrlen, qc_exists ); - payload_remainder = plen % 16; num_blocks = plen / 16; @@ -1484,7 +1475,6 @@ static sint aes_cipher(u8 *key, uint hdrlen, u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) { /* exclude ICV */ - /*static*/ /* unsigned char message[MAX_MSG_SIZE]; */ @@ -1551,13 +1541,11 @@ static sint aes_decipher(u8 *key, uint hdrlen, u8 padded_buffer[16]; u8 mic[8]; - uint frtype = GetFrameType(pframe); uint frsubtype = GetFrameSubType(pframe); frsubtype = frsubtype>>4; - memset((void *)mic_iv, 0, 16); memset((void *)mic_header1, 0, 16); memset((void *)mic_header2, 0, 16); @@ -1603,7 +1591,6 @@ static sint aes_decipher(u8 *key, uint hdrlen, } else qc_exists = 0; - /* now, decrypt pframe with hdrlen offset and plen long */ payload_index = hdrlen + 8; /* 8 is for extiv */ @@ -1649,7 +1636,6 @@ static sint aes_decipher(u8 *key, uint hdrlen, if ((hdrlen + plen+8) <= MAX_MSG_SIZE) memcpy((void *)message, pframe, (hdrlen + plen+8)); /* 8 is for ext iv len */ - pn_vector[0] = pframe[hdrlen]; pn_vector[1] = pframe[hdrlen+1]; pn_vector[2] = pframe[hdrlen+4]; @@ -1657,8 +1643,6 @@ static sint aes_decipher(u8 *key, uint hdrlen, pn_vector[4] = pframe[hdrlen+6]; pn_vector[5] = pframe[hdrlen+7]; - - construct_mic_iv( mic_iv, qc_exists, @@ -1682,7 +1666,6 @@ static sint aes_decipher(u8 *key, uint hdrlen, qc_exists ); - payload_remainder = (plen-8) % 16; num_blocks = (plen-8) / 16; @@ -1808,14 +1791,11 @@ static sint aes_decipher(u8 *key, uint hdrlen, u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) { /* exclude ICV */ - /*static*/ /* unsigned char message[MAX_MSG_SIZE]; */ - /* Intermediate Buffers */ - sint length; u8 *pframe, *prwskey; /* *payload,*iv */ struct sta_info *stainfo; @@ -1879,7 +1859,6 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) } else prwskey = &stainfo->dot118021x_UncstKey.skey[0]; - length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length); @@ -2040,6 +2019,7 @@ const u32 Te0[256] = { 0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU, }; + const u32 Td0[256] = { 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, @@ -2106,6 +2086,7 @@ const u32 Td0[256] = { 0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U, }; + const u8 Td4s[256] = { 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, @@ -2140,6 +2121,7 @@ const u8 Td4s[256] = { 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU, }; + const u8 rcons[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36 /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ @@ -2221,6 +2203,7 @@ d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3] static void *aes_encrypt_init(u8 *key, size_t len) { u32 *rk; + if (len != 16) return NULL; rk = rtw_malloc(AES_PRIV_SIZE); @@ -2235,7 +2218,6 @@ static void aes_128_encrypt(void *ctx, u8 *plain, u8 *crypt) rijndaelEncrypt(ctx, plain, crypt); } - static void gf_mulx(u8 *pad) { int i, carry; @@ -2254,7 +2236,6 @@ static void aes_encrypt_deinit(void *ctx) kfree_sensitive(ctx); } - /** * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128 * @key: 128-bit key for the hash operation @@ -2328,7 +2309,6 @@ static int omac1_aes_128_vector(u8 *key, size_t num_elem, return 0; } - /** * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC) * @key: 128-bit key for the hash operation @@ -2371,6 +2351,7 @@ u8 rtw_handle_tkip_countermeasure(struct adapter *adapter, const char *caller) if (securitypriv->btkip_countermeasure) { unsigned long passing_ms = jiffies_to_msecs(jiffies - securitypriv->btkip_countermeasure_time); + if (passing_ms > 60*1000) { DBG_871X_LEVEL(_drv_always_, "%s(%s) countermeasure time:%lus > 60s\n", caller, ADPT_ARG(adapter), passing_ms/1000); diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index dad982ed4ecf..f24ad8b1a400 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -163,6 +163,7 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) while (phead != plist) { int i; + psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); plist = get_next(plist); @@ -282,7 +283,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) rtw_init_recv_timer(preorder_ctrl); } - /* init for DM */ psta->rssi_stat.UndecoratedSmoothedPWDB = (-1); psta->rssi_stat.UndecoratedSmoothedCCK = (-1); @@ -297,7 +297,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) exit: - return psta; } @@ -315,14 +314,12 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) if (!psta) goto exit; - spin_lock_bh(&psta->lock); psta->state &= ~_FW_LINKED; spin_unlock_bh(&psta->lock); pfree_sta_queue = &pstapriv->free_sta_queue; - pstaxmitpriv = &psta->sta_xmitpriv; /* list_del_init(&psta->sleep_list); */ @@ -405,7 +402,6 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) del_timer_sync(&preorder_ctrl->reordering_ctrl_timer); - ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue; spin_lock_bh(&ppending_recvframe_queue->lock); @@ -531,7 +527,6 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) phead = &(pstapriv->sta_hash[index]); plist = get_next(phead); - while (phead != plist) { psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index c9ac5c685d74..f28536fbc4fb 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -259,12 +259,14 @@ void UpdateBrateTblForSoftAP(u8 *bssrateset, u32 bssratelen) void Save_DM_Func_Flag(struct adapter *padapter) { u8 bSaveFlag = true; + rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); } void Restore_DM_Func_Flag(struct adapter *padapter) { u8 bSaveFlag = false; + rtw_hal_set_hwreg(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag)); } @@ -304,6 +306,7 @@ inline void rtw_set_oper_ch(struct adapter *adapter, u8 ch) for (i = 0; i < dvobj->iface_nums; i++) { struct adapter *iface = dvobj->padapters[i]; + cnt += scnprintf(msg+cnt, len-cnt, " [%s:", ADPT_ARG(iface)); if (iface->mlmeextpriv.cur_channel == ch) cnt += scnprintf(msg+cnt, len-cnt, "C"); @@ -420,6 +423,7 @@ inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork) u16 get_beacon_interval(struct wlan_bssid_ex *bss) { __le16 val; + memcpy((unsigned char *)&val, rtw_get_beacon_interval_from_ie(bss->IEs), 2); return le16_to_cpu(val); @@ -493,6 +497,7 @@ void invalidate_cam_all(struct adapter *padapter) static u32 _ReadCAM(struct adapter *padapter, u32 addr) { u32 count = 0, cmd; + cmd = CAM_POLLINIG | addr; rtw_write32(padapter, RWCAM, cmd); @@ -503,9 +508,11 @@ static u32 _ReadCAM(struct adapter *padapter, u32 addr) return rtw_read32(padapter, REG_CAMREAD); } + void read_cam(struct adapter *padapter, u8 entry, u8 *get_key) { u32 j, addr, cmd; + addr = entry << 3; /* DBG_8192C("********* DUMP CAM Entry_#%02d***************\n", entry); */ @@ -1876,7 +1883,6 @@ void adaptive_early_32k(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len) /* DBG_871X("%s(): (a)bcn_cnt = %d\n", __func__, pmlmeext->bcn_cnt); - for (i = 0; i<9; i++) { DBG_871X("%s():bcn_delay_cnt[%d]=%d, bcn_delay_ratio[%d]=%d\n", __func__, i, @@ -1980,12 +1986,14 @@ void rtw_release_macid(struct adapter *padapter, struct sta_info *psta) } spin_unlock_bh(&pdvobj->lock); } + /* For 8188E RA */ u8 rtw_search_max_mac_id(struct adapter *padapter) { u8 max_mac_id = 0; struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); int i; + spin_lock_bh(&pdvobj->lock); for (i = (NUM_STA-1); i >= 0 ; i--) { if (pdvobj->macid[i] == true) @@ -2111,6 +2119,7 @@ void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip) pmlmeinfo->state & WIFI_FW_AP_STATE) { if (my_ip_ptr) { struct in_ifaddr *my_ifa_list = my_ip_ptr->ifa_list; + if (my_ifa_list) { ipaddress[0] = my_ifa_list->ifa_address & 0xFF; ipaddress[1] = (my_ifa_list->ifa_address >> 8) & 0xFF; @@ -2149,6 +2158,7 @@ void rtw_get_sec_iv(struct adapter *padapter, u8 *pcur_dot11txpn, u8 *StaAddr) pcur_dot11txpn[5], pcur_dot11txpn[6], pcur_dot11txpn[7]); } } + void rtw_set_sec_pn(struct adapter *padapter) { struct sta_info *psta; diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index aaafa38c34c4..eba29abfa832 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -398,6 +398,7 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * /* check HT op mode */ if (pattrib->ht_en) { u8 HTOpMode = pmlmeinfo->HT_protection; + if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) || (!pmlmeext->cur_bwmode && HTOpMode == 3)) { pattrib->vcs_mode = RTS_CTS; @@ -1003,6 +1004,7 @@ s32 rtw_make_wlanhdr(struct adapter *padapter, u8 *hdr, struct pkt_attrib *pattr /* Update Seq Num will be handled by f/w */ { struct sta_info *psta; + psta = rtw_get_stainfo(&padapter->stapriv, pattrib->ra); if (pattrib->psta != psta) { DBG_871X("%s, pattrib->psta(%p) != psta(%p)\n", __func__, pattrib->psta, psta); @@ -1243,6 +1245,7 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit struct ieee80211_hdr *pwlanhdr; u8 MME[_MME_IE_LENGTH_]; u32 ori_len; + mem_start = pframe = (u8 *)(pxmitframe->buf_addr) + TXDESC_OFFSET; pwlanhdr = (struct ieee80211_hdr *)pframe; -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:00 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:00 -0600 Subject: [PATCH 02/10] staging: rtl8723bs: clean up braces In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-2-ross.schm.dev@gmail.com> Add or remove braces or remove lines to fix coding style issues and clear checkpatch. WARNING: braces {} are not necessary for single statement blocks WARNING: braces {} are not necessary for any arm of this statement CHECK: Unbalanced braces around else statement CHECK: braces {} should be used on all arms of this statement CHECK: Blank lines aren't necessary before a close brace '}' CHECK: Blank lines aren't necessary after an open brace '{' Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_security.c | 42 ++++++++++--------- drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 11 +---- .../staging/rtl8723bs/core/rtw_wlan_util.c | 23 ++++++---- drivers/staging/rtl8723bs/core/rtw_xmit.c | 23 ++++++---- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 894e7beae96f..85f1164f7960 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -1336,8 +1336,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, hdrlen += 2; qc_exists = 1; - } else + } else { qc_exists = 0; + } pn_vector[0] = pframe[hdrlen]; pn_vector[1] = pframe[hdrlen+1]; @@ -1393,9 +1394,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, if (payload_remainder > 0) { for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) { + for (j = 0; j < payload_remainder; j++) padded_buffer[j] = pframe[payload_index++]; - } + bitwise_xor(aes_out, padded_buffer, chain_buffer); aes128k128d(key, chain_buffer, aes_out); } @@ -1576,20 +1577,21 @@ static sint aes_decipher(u8 *key, uint hdrlen, ((frtype|frsubtype) == WIFI_DATA_CFPOLL) || ((frtype|frsubtype) == WIFI_DATA_CFACKPOLL)) { qc_exists = 1; - if (hdrlen != WLAN_HDR_A3_QOS_LEN) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) hdrlen += 2; - } + } else if ((frtype == WIFI_DATA) && /* only for data packet . add for CONFIG_IEEE80211W, none 11w also can use */ ((frsubtype == 0x08) || (frsubtype == 0x09) || (frsubtype == 0x0a) || (frsubtype == 0x0b))) { - if (hdrlen != WLAN_HDR_A3_QOS_LEN) { + if (hdrlen != WLAN_HDR_A3_QOS_LEN) hdrlen += 2; - } + qc_exists = 1; - } else + } else { qc_exists = 0; + } /* now, decrypt pframe with hdrlen offset and plen long */ @@ -1623,9 +1625,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) { + for (j = 0; j < payload_remainder; j++) padded_buffer[j] = pframe[payload_index+j]; - } + aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, padded_buffer, chain_buffer); for (j = 0; j < payload_remainder; j++) @@ -1690,9 +1692,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, if (payload_remainder > 0) { for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) { + for (j = 0; j < payload_remainder; j++) padded_buffer[j] = message[payload_index++]; - } + bitwise_xor(aes_out, padded_buffer, chain_buffer); aes128k128d(key, chain_buffer, aes_out); } @@ -1736,9 +1738,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; - for (j = 0; j < payload_remainder; j++) { + for (j = 0; j < payload_remainder; j++) padded_buffer[j] = message[payload_index+j]; - } + aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, padded_buffer, chain_buffer); for (j = 0; j < payload_remainder; j++) @@ -1758,9 +1760,8 @@ static sint aes_decipher(u8 *key, uint hdrlen, for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; - for (j = 0; j < 8; j++) { + for (j = 0; j < 8; j++) padded_buffer[j] = message[j+hdrlen+8+plen-8]; - } aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, padded_buffer, chain_buffer); @@ -1856,8 +1857,9 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) res = _FAIL; goto exit; } - } else + } else { prwskey = &stainfo->dot118021x_UncstKey.skey[0]; + } length = ((union recv_frame *)precvframe)->u.hdr.len-prxattrib->hdrlen-prxattrib->iv_len; @@ -1941,11 +1943,13 @@ u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe) if (!memcmp(mic, pframe+pattrib->pkt_len-8, 8)) { pmlmeext->mgnt_80211w_IPN_rx = temp_ipn; res = _SUCCESS; - } else + } else { DBG_871X("BIP MIC error!\n"); + } - } else + } else { res = RTW_RX_HANDLED; + } BIP_exit: kfree(BIP_AAD); diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index f24ad8b1a400..6e9785c21cf8 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -154,7 +154,6 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) int index; if (pstapriv) { - /*delete all reordering_ctrl_timer */ spin_lock_bh(&pstapriv->sta_hash_lock); for (index = 0; index < NUM_STA; index++) { @@ -179,7 +178,6 @@ u32 _rtw_free_sta_priv(struct sta_priv *pstapriv) kfree_sta_priv_lock(pstapriv); vfree(pstapriv->pallocated_stainfo_buf); - } return _SUCCESS; } @@ -241,9 +239,8 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) /* In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */ /* So, we initialize the tid_rxseq variable as the 0xffff. */ - for (i = 0; i < 16; i++) { + for (i = 0; i < 16; i++) memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); - } RT_TRACE( _module_rtl871x_sta_mgt_c_, @@ -292,7 +289,6 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) spin_unlock_bh(&(pstapriv->sta_hash_lock)); /* alloc mac id for non-bc/mc station, */ rtw_alloc_macid(pstapriv->padapter, psta); - } exit: @@ -420,7 +416,6 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) } spin_unlock_bh(&ppending_recvframe_queue->lock); - } if (!(psta->state & WIFI_AP_STATE)) @@ -496,7 +491,6 @@ void rtw_free_all_stainfo(struct adapter *padapter) if (pbcmc_stainfo != psta) rtw_free_stainfo(padapter, psta); - } } @@ -528,7 +522,6 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) plist = get_next(phead); while (phead != plist) { - psta = LIST_CONTAINOR(plist, struct sta_info, hash_list); if ((!memcmp(psta->hwaddr, addr, ETH_ALEN))) @@ -545,7 +538,6 @@ struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) u32 rtw_init_bcmc_stainfo(struct adapter *padapter) { - struct sta_info *psta; u32 res = _SUCCESS; NDIS_802_11_MAC_ADDRESS bcast_addr = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; @@ -598,7 +590,6 @@ u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr) match = true; break; } - } spin_unlock_bh(&(pacl_node_q->lock)); diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index f28536fbc4fb..2fedaa1b4870 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -957,9 +957,10 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_ if (pmlmeext->cur_channel > 14) { if ((pregistrypriv->bw_mode & 0xf0) > 0) cbw40_enable = 1; - } else + } else { if ((pregistrypriv->bw_mode & 0x0f) > 0) cbw40_enable = 1; + } if ((pHT_info->infos[0] & BIT(2)) && cbw40_enable) { new_bwmode = CHANNEL_WIDTH_40; @@ -991,8 +992,9 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_ /* update HT info also */ HT_info_handler(padapter, pIE); - } else + } else { pmlmeinfo->bwmode_updated = false; + } if (true == pmlmeinfo->bwmode_updated) { struct sta_info *psta; @@ -1521,8 +1523,9 @@ unsigned int is_ap_in_tkip(struct adapter *padapter) } return false; - } else + } else { return false; + } } int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode) @@ -1626,8 +1629,9 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) { DBG_871X("link to Airgo Cap\n"); return HT_IOT_PEER_AIRGO; - } else + } else { break; + } default: break; @@ -1697,23 +1701,24 @@ void update_capinfo(struct adapter *Adapter, u16 updateCap) } } - if (updateCap & cIBSS) + if (updateCap & cIBSS) { /* Filen: See 802.11-2007 p.91 */ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; - else { + } else { /* Filen: See 802.11-2007 p.90 */ - if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11A | WIRELESS_11_5N | WIRELESS_11AC)) + if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N | WIRELESS_11A | WIRELESS_11_5N | WIRELESS_11AC)) { pmlmeinfo->slotTime = SHORT_SLOT_TIME; - else if (pmlmeext->cur_wireless_mode & (WIRELESS_11G)) { + } else if (pmlmeext->cur_wireless_mode & (WIRELESS_11G)) { if ((updateCap & cShortSlotTime) /* && (!(pMgntInfo->pHTInfo->RT2RT_HT_Mode & RT_HT_CAP_USE_LONG_PREAMBLE)) */) /* Short Slot Time */ pmlmeinfo->slotTime = SHORT_SLOT_TIME; else /* Long Slot Time */ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; - } else + } else { /* B Mode */ pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME; + } } rtw_hal_set_hwreg(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime); diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index eba29abfa832..af23c649a870 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -366,9 +366,9 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * /* Other fragments are protected by previous fragment. */ /* So we only need to check the length of first fragment. */ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { - if (sz > padapter->registrypriv.rts_thresh) + if (sz > padapter->registrypriv.rts_thresh) { pattrib->vcs_mode = RTS_CTS; - else { + } else { if (pattrib->rtsen) pattrib->vcs_mode = RTS_CTS; else if (pattrib->cts2self) @@ -676,8 +676,9 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib memcpy(pattrib->ra, pattrib->dst, ETH_ALEN); memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN); DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_ap); - } else + } else { DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib_unknown); + } pattrib->pktlen = pktfile.pkt_len; @@ -923,8 +924,9 @@ static s32 xmitframe_swencrypt(struct adapter *padapter, struct xmit_frame *pxmi default: break; } - } else + } else { RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_, ("### xmitframe_hwencrypt\n")); + } return _SUCCESS; } @@ -1202,8 +1204,9 @@ s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_fram ClearMFrag(mem_start); break; - } else + } else { RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__)); + } addr = (SIZE_PTR)(pframe); @@ -1445,17 +1448,18 @@ void rtw_update_protection(struct adapter *padapter, u8 *ie, uint ie_len) case AUTO_VCS: default: perp = rtw_get_ie(ie, _ERPINFO_IE_, &erp_len, ie_len); - if (!perp) + if (!perp) { pxmitpriv->vcs = NONE_VCS; - else { + } else { protection = (*(perp + 2)) & BIT(1); if (protection) { if (pregistrypriv->vcs_type == RTS_CTS) pxmitpriv->vcs = RTS_CTS; else pxmitpriv->vcs = CTS_TO_SELF; - } else + } else { pxmitpriv->vcs = NONE_VCS; + } } break; @@ -1508,8 +1512,9 @@ static struct xmit_buf *__rtw_alloc_cmd_xmitbuf(struct xmit_priv *pxmitpriv, DBG_871X("%s pxmitbuf->sctx is not NULL\n", __func__); rtw_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC); } - } else + } else { DBG_871X("%s fail, no xmitbuf available !!!\n", __func__); + } return pxmitbuf; } -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:01 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:01 -0600 Subject: [PATCH 03/10] staging: rtl8723bs: clean up space before tabs In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-3-ross.schm.dev@gmail.com> Remove spaces before tabs to fix coding style issues and clear checkpatch warnings. WARNING: please, no space before tabs Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 16 +++---- drivers/staging/rtl8723bs/core/rtw_recv.c | 42 +++++++++--------- drivers/staging/rtl8723bs/core/rtw_security.c | 44 +++++++++---------- .../staging/rtl8723bs/core/rtw_wlan_util.c | 34 +++++++------- drivers/staging/rtl8723bs/core/rtw_xmit.c | 20 ++++----- 5 files changed, 78 insertions(+), 78 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 0d8aa7a2469e..8fe1d7429760 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -1340,8 +1340,8 @@ void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason) { struct pwrctrl_priv *pwrpriv; -/* DBG_871X("+" FUNC_ADPT_FMT ": Request PS deny for %d (0x%08X)\n", */ -/* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ + /* DBG_871X("+" FUNC_ADPT_FMT ": Request PS deny for %d (0x%08X)\n", */ + /* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ pwrpriv = adapter_to_pwrctl(padapter); @@ -1353,8 +1353,8 @@ void rtw_ps_deny(struct adapter *padapter, enum PS_DENY_REASON reason) pwrpriv->ps_deny |= BIT(reason); mutex_unlock(&pwrpriv->lock); -/* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ -/* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ + /* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ + /* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ } /* @@ -1366,8 +1366,8 @@ void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason) struct pwrctrl_priv *pwrpriv; -/* DBG_871X("+" FUNC_ADPT_FMT ": Cancel PS deny for %d(0x%08X)\n", */ -/* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ + /* DBG_871X("+" FUNC_ADPT_FMT ": Cancel PS deny for %d(0x%08X)\n", */ + /* FUNC_ADPT_ARG(padapter), reason, BIT(reason)); */ pwrpriv = adapter_to_pwrctl(padapter); @@ -1379,8 +1379,8 @@ void rtw_ps_deny_cancel(struct adapter *padapter, enum PS_DENY_REASON reason) pwrpriv->ps_deny &= ~BIT(reason); mutex_unlock(&pwrpriv->lock); -/* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ -/* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ + /* DBG_871X("-" FUNC_ADPT_FMT ": Now PS deny for 0x%08X\n", */ + /* FUNC_ADPT_ARG(padapter), pwrpriv->ps_deny); */ } /* diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index 26e72decb07e..c854aa3ff992 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -25,7 +25,7 @@ void _rtw_init_sta_recv_priv(struct sta_recv_priv *psta_recvpriv) spin_lock_init(&psta_recvpriv->lock); /* for (i = 0; iblk_strms[i]); */ + /* _rtw_init_queue(&psta_recvpriv->blk_strms[i]); */ _rtw_init_queue(&psta_recvpriv->defrag_q); } @@ -55,7 +55,7 @@ sint _rtw_init_recv_priv(struct recv_priv *precvpriv, struct adapter *padapter) precvpriv->precv_frame_buf = (u8 *)N_BYTE_ALIGMENT((SIZE_PTR)(precvpriv->pallocated_frame_buf), RXFRAME_ALIGN_SZ); /* precvpriv->precv_frame_buf = precvpriv->pallocated_frame_buf + RXFRAME_ALIGN_SZ - */ - /* ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); */ + /* ((SIZE_PTR) (precvpriv->pallocated_frame_buf) &(RXFRAME_ALIGN_SZ-1)); */ precvframe = (union recv_frame *) precvpriv->precv_frame_buf; @@ -316,9 +316,9 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) u8 *pframe, *payload, *pframemic; u8 *mickey; /* u8 *iv, rxdata_key_idx = 0; */ - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib; - struct security_priv *psecuritypriv = &adapter->securitypriv; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &precvframe->u.hdr.attrib; + struct security_priv *psecuritypriv = &adapter->securitypriv; struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -340,7 +340,7 @@ sint recvframe_chkmic(struct adapter *adapter, union recv_frame *precvframe) RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("\n recvframe_chkmic: bcmc key\n")); /* DBG_871X("\n recvframe_chkmic: bcmc key psecuritypriv->dot118021XGrpKeyid(%d), pmlmeinfo->key_index(%d) , recv key_id(%d)\n", */ - /* psecuritypriv->dot118021XGrpKeyid, pmlmeinfo->key_index, rxdata_key_idx); */ + /* psecuritypriv->dot118021XGrpKeyid, pmlmeinfo->key_index, rxdata_key_idx); */ if (psecuritypriv->binstallGrpkey == false) { res = _FAIL; @@ -600,13 +600,13 @@ union recv_frame *portctrl(struct adapter *adapter, union recv_frame *precv_fram prtnframe = precv_frame; /* check is the EAPOL frame or not (Rekey) */ /* if (ether_type == eapol_type) { */ - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type == 0x888e\n")); */ + /* RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_, ("########portctrl:ether_type == 0x888e\n")); */ /* check Rekey */ - /* prtnframe =precv_frame; */ + /* prtnframe =precv_frame; */ /* */ /* else { */ - /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type = 0x%04x\n", ether_type)); */ + /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:ether_type = 0x%04x\n", ether_type)); */ /* */ } } else @@ -735,11 +735,11 @@ void process_wmmps_data(struct adapter *padapter, union recv_frame *precv_frame) void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta); void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct sta_info *sta) { - int sz; - struct sta_info *psta = NULL; - struct stainfo_stats *pstats = NULL; - struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; - struct recv_priv *precvpriv = &padapter->recvpriv; + int sz; + struct sta_info *psta = NULL; + struct stainfo_stats *pstats = NULL; + struct rx_pkt_attrib *pattrib = &prframe->u.hdr.attrib; + struct recv_priv *precvpriv = &padapter->recvpriv; sz = get_recvframe_len(prframe); precvpriv->rx_bytes += sz; @@ -779,8 +779,8 @@ sint sta2sta_data_frame( u8 *ptr = precv_frame->u.hdr.rx_data; sint ret = _SUCCESS; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; u8 *mybssid = get_bssid(pmlmepriv); u8 *myhwaddr = myid(&adapter->eeprompriv); u8 *sta_addr = NULL; @@ -878,8 +878,8 @@ sint ap2sta_data_frame( u8 *ptr = precv_frame->u.hdr.rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; sint ret = _SUCCESS; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; u8 *mybssid = get_bssid(pmlmepriv); u8 *myhwaddr = myid(&adapter->eeprompriv); sint bmcast = IS_MCAST(pattrib->dst); @@ -1026,8 +1026,8 @@ sint sta2ap_data_frame( { u8 *ptr = precv_frame->u.hdr.rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; - struct sta_priv *pstapriv = &adapter->stapriv; - struct mlme_priv *pmlmepriv = &adapter->mlmepriv; + struct sta_priv *pstapriv = &adapter->stapriv; + struct mlme_priv *pmlmepriv = &adapter->mlmepriv; unsigned char *mybssid = get_bssid(pmlmepriv); sint ret = _SUCCESS; @@ -2557,7 +2557,7 @@ s32 rtw_recv_entry(union recv_frame *precvframe) struct recv_priv *precvpriv; s32 ret = _SUCCESS; -/* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+rtw_recv_entry\n")); */ + /* RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("+rtw_recv_entry\n")); */ padapter = precvframe->u.hdr.adapter; diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 85f1164f7960..41b80e433cc2 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -221,10 +221,10 @@ void rtw_wep_encrypt(struct adapter *padapter, u8 *pxmitframe) u8 *pframe, *payload, *iv; /* wepkey */ u8 wepkey[16]; - u8 hw_hdr_offset = 0; - struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u8 hw_hdr_offset = 0; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) return; @@ -664,9 +664,9 @@ u32 rtw_tkip_encrypt(struct adapter *padapter, u8 *pxmitframe) u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; - struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u32 res = _SUCCESS; if (((struct xmit_frame *)pxmitframe)->buf_addr == NULL) @@ -740,10 +740,10 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) u8 *pframe, *payload, *iv, *prwskey; union pn48 dot11txpn; - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - u32 res = _SUCCESS; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + u32 res = _SUCCESS; pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; @@ -1477,15 +1477,15 @@ u32 rtw_aes_encrypt(struct adapter *padapter, u8 *pxmitframe) { /* exclude ICV */ /*static*/ -/* unsigned char message[MAX_MSG_SIZE]; */ + /* unsigned char message[MAX_MSG_SIZE]; */ /* Intermediate Buffers */ - sint curfragnum, length; + sint curfragnum, length; u8 *pframe, *prwskey; /* *payload,*iv */ - u8 hw_hdr_offset = 0; - struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + u8 hw_hdr_offset = 0; + struct pkt_attrib *pattrib = &((struct xmit_frame *)pxmitframe)->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u32 res = _SUCCESS; @@ -1793,15 +1793,15 @@ u32 rtw_aes_decrypt(struct adapter *padapter, u8 *precvframe) { /* exclude ICV */ /*static*/ -/* unsigned char message[MAX_MSG_SIZE]; */ + /* unsigned char message[MAX_MSG_SIZE]; */ /* Intermediate Buffers */ - sint length; + sint length; u8 *pframe, *prwskey; /* *payload,*iv */ - struct sta_info *stainfo; - struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; + struct sta_info *stainfo; + struct rx_pkt_attrib *prxattrib = &((union recv_frame *)precvframe)->u.hdr.attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; u32 res = _SUCCESS; pframe = (unsigned char *)((union recv_frame *)precvframe)->u.hdr.rx_data; diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index 2fedaa1b4870..a6176e86f370 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -802,7 +802,7 @@ void WMMOnAssocRsp(struct adapter *padapter) u32 edca[4], inx[4]; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; struct registry_priv *pregpriv = &padapter->registrypriv; acm_mask = 0; @@ -937,7 +937,7 @@ static void bwmode_update_check(struct adapter *padapter, struct ndis_80211_var_ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); struct registry_priv *pregistrypriv = &padapter->registrypriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; u8 cbw40_enable = 0; if (!pIE) @@ -1030,8 +1030,8 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) u8 cur_ldpc_cap = 0, cur_stbc_cap = 0; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; if (!pIE) return; @@ -1043,8 +1043,8 @@ void HT_caps_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) for (i = 0; i < (pIE->Length); i++) { if (i != 2) { - /* Commented by Albert 2010/07/12 */ - /* Got the endian issue here. */ + /* Commented by Albert 2010/07/12 */ + /* Got the endian issue here. */ pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]); } else { /* modify from fw by Thomas 2010/11/17 */ @@ -1113,8 +1113,8 @@ void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) { struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct ht_priv *phtpriv = &pmlmepriv->htpriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + struct ht_priv *phtpriv = &pmlmepriv->htpriv; if (!pIE) return; @@ -1131,8 +1131,8 @@ void HT_info_handler(struct adapter *padapter, struct ndis_80211_var_ie *pIE) void HTOnAssocRsp(struct adapter *padapter) { - unsigned char max_AMPDU_len; - unsigned char min_MPDU_spacing; + unsigned char max_AMPDU_len; + unsigned char min_MPDU_spacing; /* struct registry_priv *pregpriv = &padapter->registrypriv; */ struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -1229,8 +1229,8 @@ void update_ldpc_stbc_cap(struct sta_info *psta) int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) { - unsigned int len; - unsigned char *p; + unsigned int len; + unsigned char *p; unsigned short val16, subtype; struct wlan_network *cur_network = &(Adapter->mlmepriv.cur_network); /* u8 wpa_ie[255], rsn_ie[255]; */ @@ -1530,7 +1530,7 @@ unsigned int is_ap_in_tkip(struct adapter *padapter) int support_short_GI(struct adapter *padapter, struct HT_caps_element *pHT_caps, u8 bwmode) { - unsigned char bit_offset; + unsigned char bit_offset; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); @@ -1604,7 +1604,7 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) if (pIE->Length >= 5) { if (pIE->data[4] == 1) /* if (pIE->data[5] & RT_HT_CAP_USE_LONG_PREAMBLE) */ - /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */ + /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_LONG_PREAMBLE; */ if (pIE->data[5] & RT_HT_CAP_USE_92SE) /* bssDesc->BssHT.RT2RT_HT_Mode |= RT_HT_CAP_USE_92SE; */ Vender = HT_IOT_PEER_REALTEK_92SE; @@ -1730,8 +1730,8 @@ void update_wireless_mode(struct adapter *padapter) u32 SIFS_Timer; struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); - unsigned char *rate = cur_network->SupportedRates; + struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network); + unsigned char *rate = cur_network->SupportedRates; if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) pmlmeinfo->HT_enable = 1; @@ -2141,7 +2141,7 @@ void rtw_get_current_ip_address(struct adapter *padapter, u8 *pcurrentip) #ifdef CONFIG_WOWLAN void rtw_get_sec_iv(struct adapter *padapter, u8 *pcur_dot11txpn, u8 *StaAddr) { - struct sta_info *psta; + struct sta_info *psta; struct security_priv *psecpriv = &padapter->securitypriv; memset(pcur_dot11txpn, 0, 8); diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index af23c649a870..391bc666f7a6 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -363,8 +363,8 @@ static void update_attrib_vcs_info(struct adapter *padapter, struct xmit_frame * /* (1) RTS_Threshold is compared to the MPDU, not MSDU. */ /* (2) If there are more than one frag in this MSDU, only the first frag uses protection frame. */ - /* Other fragments are protected by previous fragment. */ - /* So we only need to check the length of first fragment. */ + /* Other fragments are protected by previous fragment. */ + /* So we only need to check the length of first fragment. */ if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N || padapter->registrypriv.wifi_spec) { if (sz > padapter->registrypriv.rts_thresh) { pattrib->vcs_mode = RTS_CTS; @@ -648,9 +648,9 @@ static s32 update_attrib(struct adapter *padapter, _pkt *pkt, struct pkt_attrib struct ethhdr etherhdr; sint bmcast; - struct sta_priv *pstapriv = &padapter->stapriv; + struct sta_priv *pstapriv = &padapter->stapriv; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct qos_priv *pqospriv = &pmlmepriv->qospriv; + struct qos_priv *pqospriv = &pmlmepriv->qospriv; sint res = _SUCCESS; DBG_COUNTER(padapter->tx_logs.core_tx_upd_attrib); @@ -812,10 +812,10 @@ static s32 xmitframe_addmic(struct adapter *padapter, struct xmit_frame *pxmitfr { sint curfragnum, length; u8 *pframe, *payload, mic[8]; - struct mic_data micdata; - struct pkt_attrib *pattrib = &pxmitframe->attrib; - struct security_priv *psecuritypriv = &padapter->securitypriv; - struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct mic_data micdata; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct security_priv *psecuritypriv = &padapter->securitypriv; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; u8 priority[4] = {0x0, 0x0, 0x0, 0x0}; u8 hw_hdr_offset = 0; sint bmcst = IS_MCAST(pattrib->ra); @@ -1237,8 +1237,8 @@ s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit { u8 *pframe, *mem_start = NULL, *tmp_buf = NULL; u8 subtype; - struct sta_info *psta = NULL; - struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct sta_info *psta = NULL; + struct pkt_attrib *pattrib = &pxmitframe->attrib; s32 bmcst = IS_MCAST(pattrib->ra); u8 *BIP_AAD = NULL; u8 *MGMT_body = NULL; -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:03 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:03 -0600 Subject: [PATCH 05/10] staging: rtl8723bs: clean up open braces In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-5-ross.schm.dev@gmail.com> Move braces to fix coding style issues and clear checkpatch errors. Some braces are removed for single statements. ERROR: open brace '{' following function definitions go on the next line ERROR: that open brace { should be on the previous line Signed-off-by: Ross Schmidt --- .../staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 167 ++++++------------ 1 file changed, 54 insertions(+), 113 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 736f1a6ac118..385705aafa5c 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -1746,8 +1746,7 @@ static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv, u32 ciph return -ENOTSUPP; } - if (ucast) - { + if (ucast) { psecuritypriv->ndisencryptstatus = ndisencryptstatus; /* if (psecuritypriv->dot11PrivacyAlgrthm >= _AES_) */ @@ -1819,10 +1818,8 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel } pwpa = rtw_get_wpa_ie(buf, &wpa_ielen, ielen); - if (pwpa && wpa_ielen > 0) - { - if (rtw_parse_wpa_ie(pwpa, wpa_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) - { + if (pwpa && wpa_ielen > 0) { + if (rtw_parse_wpa_ie(pwpa, wpa_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPAPSK; memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0], wpa_ielen+2); @@ -1832,10 +1829,8 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel } pwpa2 = rtw_get_wpa2_ie(buf, &wpa2_ielen, ielen); - if (pwpa2 && wpa2_ielen > 0) - { - if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) - { + if (pwpa2 && wpa2_ielen > 0) { + if (rtw_parse_wpa2_ie(pwpa2, wpa2_ielen+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) { padapter->securitypriv.dot11AuthAlgrthm = dot11AuthAlgrthm_8021X; padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeWPA2PSK; memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0], wpa2_ielen+2); @@ -1845,13 +1840,10 @@ static int rtw_cfg80211_set_wpa_ie(struct adapter *padapter, u8 *pie, size_t iel } if (group_cipher == 0) - { group_cipher = WPA_CIPHER_NONE; - } + if (pairwise_cipher == 0) - { pairwise_cipher = WPA_CIPHER_NONE; - } switch (group_cipher) { @@ -1954,8 +1946,7 @@ static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - if (!params->ssid || !params->ssid_len) - { + if (!params->ssid || !params->ssid_len) { ret = -EINVAL; goto exit; } @@ -1981,8 +1972,7 @@ static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev, ret = rtw_cfg80211_set_auth_type(psecuritypriv, NL80211_AUTHTYPE_OPEN_SYSTEM); rtw_set_802_11_authentication_mode(padapter, psecuritypriv->ndisauthtype); - if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) - { + if (rtw_set_802_11_ssid(padapter, &ndis_ssid) == false) { ret = -1; goto exit; } @@ -2004,8 +1994,7 @@ static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev) rtw_set_to_roam(padapter, 0); - if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) - { + if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) { rtw_scan_abort(padapter); LeaveAllPowerSaveMode(padapter); @@ -2041,8 +2030,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, sme->privacy, sme->key, sme->key_len, sme->key_idx); - if (adapter_wdev_data(padapter)->block == true) - { + if (adapter_wdev_data(padapter)->block == true) { ret = -EBUSY; DBG_871X("%s wdev_priv.block is set\n", __func__); goto exit; @@ -2059,8 +2047,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - if (!sme->ssid || !sme->ssid_len) - { + if (!sme->ssid || !sme->ssid_len) { ret = -EINVAL; goto exit; } @@ -2119,10 +2106,8 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, } /* For WEP Shared auth */ - if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared - || psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && sme->key - ) - { + if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared || + psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) && sme->key) { u32 wep_key_idx, wep_key_len, wep_total_len; struct ndis_802_11_wep *pwep = NULL; DBG_871X("%s(): Shared/Auto WEP\n", __func__); @@ -2135,8 +2120,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, goto exit; } - if (wep_key_len > 0) - { + if (wep_key_len > 0) { wep_key_len = wep_key_len <= 5 ? 5 : 13; wep_total_len = wep_key_len + FIELD_OFFSET(struct ndis_802_11_wep, KeyMaterial); pwep = rtw_malloc(wep_total_len); @@ -2151,13 +2135,11 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, pwep->KeyLength = wep_key_len; pwep->Length = wep_total_len; - if (wep_key_len == 13) - { + if (wep_key_len == 13) { padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; } - } - else { + } else { ret = -EINVAL; goto exit; } @@ -2168,9 +2150,7 @@ static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev, memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength); if (rtw_set_802_11_add_wep(padapter, pwep) == (u8)_FAIL) - { ret = -EOPNOTSUPP; - } kfree(pwep); @@ -2290,17 +2270,14 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); if (!memcmp((u8 *)pmksa->bssid, strZeroMacAddress, ETH_ALEN)) - { return -EINVAL; - } blInserted = false; /* overwrite PMKID */ - for (index = 0 ; index < NUM_PMKID_CACHE; index++) - { - if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) - { /* BSSID is matched, the same AP => rewrite with new PMKID. */ + for (index = 0 ; index < NUM_PMKID_CACHE; index++) { + if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) { + /* BSSID is matched, the same AP => rewrite with new PMKID. */ DBG_871X(FUNC_NDEV_FMT" BSSID exists in the PMKList.\n", FUNC_NDEV_ARG(ndev)); memcpy(psecuritypriv->PMKIDList[index].PMKID, (u8 *)pmksa->pmkid, WLAN_PMKID_LEN); @@ -2311,8 +2288,7 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, } } - if (!blInserted) - { + if (!blInserted) { /* Find a new entry */ DBG_871X(FUNC_NDEV_FMT" Use the new entry index = %d for this PMKID.\n", FUNC_NDEV_ARG(ndev), psecuritypriv->PMKIDIndex); @@ -2323,9 +2299,7 @@ static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy, psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed = true; psecuritypriv->PMKIDIndex++; if (psecuritypriv->PMKIDIndex == 16) - { psecuritypriv->PMKIDIndex = 0; - } } return 0; @@ -2341,10 +2315,12 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, DBG_871X(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - for (index = 0 ; index < NUM_PMKID_CACHE; index++) - { - if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) - { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ + for (index = 0 ; index < NUM_PMKID_CACHE; index++) { + if (!memcmp(psecuritypriv->PMKIDList[index].Bssid, (u8 *)pmksa->bssid, ETH_ALEN)) { + /* + * BSSID is matched, the same AP => Remove this PMKID information + * and reset it. + */ eth_zero_addr(psecuritypriv->PMKIDList[index].Bssid); memset(psecuritypriv->PMKIDList[index].PMKID, 0x00, WLAN_PMKID_LEN); psecuritypriv->PMKIDList[index].bUsed = false; @@ -2353,8 +2329,7 @@ static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy, } } - if (false == bMatched) - { + if (false == bMatched) { DBG_871X(FUNC_NDEV_FMT" do not have matched BSSID\n" , FUNC_NDEV_ARG(ndev)); return -EINVAL; @@ -2441,8 +2416,7 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc if (unlikely(skb->len < rtap_len)) goto fail; - if (rtap_len != 14) - { + if (rtap_len != 14) { DBG_8192C("radiotap len (should be 14): %d\n", rtap_len); goto fail; } @@ -2478,11 +2452,8 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc /* Use the real net device to transmit the packet */ return _rtw_xmit_entry(skb, padapter->pnetdev); - } - else if ((frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) - == (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION) - ) - { + } else if ((frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) == + (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION)) { /* only for action frames */ struct xmit_frame *pmgntframe; struct pkt_attrib *pattrib; @@ -2511,9 +2482,7 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc /* starting alloc mgmt frame to dump it */ if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) - { goto fail; - } /* update attribute */ pattrib = &pmgntframe->attrib; @@ -2538,9 +2507,7 @@ static netdev_tx_t rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb, struc dump_mgntframe(padapter, pmgntframe); - } - else - { + } else { DBG_8192C("frame_control = 0x%x\n", frame_control & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)); } @@ -2738,12 +2705,9 @@ static int rtw_add_beacon(struct adapter *adapter, const u8 *head, size_t head_l rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, P2P_OUI, 4); rtw_ies_remove_ie(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_, WFD_OUI, 4); - if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) - { + if (rtw_check_beacon_data(adapter, pbuf, len) == _SUCCESS) { ret = 0; - } - else - { + } else { ret = -EINVAL; } @@ -2819,15 +2783,13 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev DBG_871X("+"FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev)); - if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) - { + if (check_fwstate(pmlmepriv, (_FW_LINKED|WIFI_AP_STATE)) != true) { DBG_8192C("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n", __func__); return -EINVAL; } - if (!mac) - { + if (!mac) { DBG_8192C("flush all sta, and cam_entry\n"); flush_all_cam_entry(padapter); /* clear CAM */ @@ -2842,8 +2804,7 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev if (mac[0] == 0xff && mac[1] == 0xff && mac[2] == 0xff && mac[3] == 0xff && - mac[4] == 0xff && mac[5] == 0xff) - { + mac[4] == 0xff && mac[5] == 0xff) { return -EINVAL; } @@ -2854,20 +2815,15 @@ static int cfg80211_rtw_del_station(struct wiphy *wiphy, struct net_device *ndev plist = get_next(phead); /* check asoc_queue */ - while (phead != plist) - { + while (phead != plist) { psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); plist = get_next(plist); - if (!memcmp((u8 *)mac, psta->hwaddr, ETH_ALEN)) - { - if (psta->dot8021xalg == 1 && psta->bpairwise_key_installed == false) - { + if (!memcmp((u8 *)mac, psta->hwaddr, ETH_ALEN)) { + if (psta->dot8021xalg == 1 && psta->bpairwise_key_installed == false) { DBG_8192C("%s, sta's dot8021xalg = 1 and key_installed = false\n", __func__); - } - else - { + } else { DBG_8192C("free psta =%p, aid =%d\n", psta, psta->aid); list_del_init(&psta->asoc_list); @@ -2913,8 +2869,7 @@ static struct sta_info *rtw_sta_info_get_by_idx(const int idx, struct sta_priv * plist = get_next(phead); /* check asoc_queue */ - while (phead != plist) - { + while (phead != plist) { if (idx == i) psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); plist = get_next(plist); i++; @@ -2935,8 +2890,7 @@ static int cfg80211_rtw_dump_station(struct wiphy *wiphy, struct net_device *nde spin_lock_bh(&pstapriv->asoc_list_lock); psta = rtw_sta_info_get_by_idx(idx, pstapriv); spin_unlock_bh(&pstapriv->asoc_list_lock); - if (NULL == psta) - { + if (NULL == psta) { DBG_871X("Station is not found\n"); ret = -ENOENT; goto exit; @@ -2998,8 +2952,7 @@ static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *b } /* starting alloc mgmt frame to dump it */ - if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) - { + if ((pmgntframe = alloc_mgtxmitframe(pxmitpriv)) == NULL) { /* ret = -ENOMEM; */ ret = _FAIL; goto exit; @@ -3025,18 +2978,14 @@ static int _cfg80211_rtw_mgmt_tx(struct adapter *padapter, u8 tx_ch, const u8 *b pattrib->last_txcmdsz = pattrib->pktlen; - if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) - { + if (dump_mgntframe_and_wait_ack(padapter, pmgntframe) != _SUCCESS) { ack = false; ret = _FAIL; #ifdef DEBUG_CFG80211 DBG_8192C("%s, ack == _FAIL\n", __func__); #endif - } - else - { - + } else { msleep(50); #ifdef DEBUG_CFG80211 @@ -3129,9 +3078,7 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, rtw_clear_scan_deny(padapter); break; case P2P_INVIT_RESP: - if (pwdev_priv->invit_info.flags & BIT(0) - && pwdev_priv->invit_info.status == 0) - { + if (pwdev_priv->invit_info.flags & BIT(0) && pwdev_priv->invit_info.status == 0) { DBG_871X(FUNC_ADPT_FMT" agree with invitation of persistent group\n", FUNC_ADPT_ARG(padapter)); rtw_set_scan_deny(padapter, 5000); @@ -3148,10 +3095,9 @@ static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, } #if defined(CONFIG_PNO_SUPPORT) -static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, - struct net_device *dev, - struct cfg80211_sched_scan_request *request) { - +static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_sched_scan_request *request) +{ struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); int ret; @@ -3190,8 +3136,8 @@ static int cfg80211_rtw_sched_scan_start(struct wiphy *wiphy, return ret; } -static int cfg80211_rtw_sched_scan_stop(struct wiphy *wiphy, - struct net_device *dev) { +static int cfg80211_rtw_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev) +{ return rtw_android_pno_enable(dev, false); } #endif /* CONFIG_PNO_SUPPORT */ @@ -3229,24 +3175,19 @@ static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap, enum *if BW_40 rx_mask[4]= 0x01; *highest supported RX rate */ - if (rf_type == RF_1T1R) - { + if (rf_type == RF_1T1R) { ht_cap->mcs.rx_mask[0] = 0xFF; ht_cap->mcs.rx_mask[1] = 0x00; ht_cap->mcs.rx_mask[4] = 0x01; ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS7); - } - else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) - { + } else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) { ht_cap->mcs.rx_mask[0] = 0xFF; ht_cap->mcs.rx_mask[1] = 0xFF; ht_cap->mcs.rx_mask[4] = 0x01; ht_cap->mcs.rx_highest = cpu_to_le16(MAX_BIT_RATE_40MHZ_MCS15); - } - else - { + } else { DBG_8192C("%s, error rf_type =%d\n", __func__, rf_type); } -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:05 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:05 -0600 Subject: [PATCH 07/10] staging: rtl8723bs: clean up trailing statements In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-7-ross.schm.dev@gmail.com> Move trailing statements to the next line to fix coding style issues and clear checkpatch errors. ERROR: trailing statements should be on next line Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 3 ++- drivers/staging/rtl8723bs/os_dep/ioctl_linux.c | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 385705aafa5c..7676056913d8 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -2870,7 +2870,8 @@ static struct sta_info *rtw_sta_info_get_by_idx(const int idx, struct sta_priv * /* check asoc_queue */ while (phead != plist) { - if (idx == i) psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); + if (idx == i) + psta = LIST_CONTAINOR(plist, struct sta_info, asoc_list); plist = get_next(plist); i++; } diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 773e4816fbc4..9c00469deeab 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -3151,7 +3151,8 @@ static int rtw_dbg_port(struct net_device *dev, #endif case 0xaa: { - if ((extra_arg & 0x7F) > 0x3F) extra_arg = 0xFF; + if ((extra_arg & 0x7F) > 0x3F) + extra_arg = 0xFF; DBG_871X("chang data rate to :0x%02x\n", extra_arg); padapter->fix_rate = extra_arg; } @@ -4934,7 +4935,8 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ count = 0; do { str = strsep(&ptr, delim); - if (NULL == str) break; + if (NULL == str) + break; sscanf(str, "%i", &temp); buffer[count++] = (u8)temp; } while (1); @@ -4952,7 +4954,8 @@ static int rtw_ioctl_wext_private(struct net_device *dev, union iwreq_data *wrq_ count = 0; do { str = strsep(&ptr, delim); - if (NULL == str) break; + if (NULL == str) + break; sscanf(str, "%i", &temp); ((s32 *)buffer)[count++] = (s32)temp; } while (1); -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:04 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:04 -0600 Subject: [PATCH 06/10] staging: rtl8723bs: clean up switch case indentation In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-6-ross.schm.dev@gmail.com> Move cases to align with switch indentation to fix coding style issues and clear checkpatch errors. ERROR: switch and case should be at the same indent Signed-off-by: Ross Schmidt --- .../staging/rtl8723bs/os_dep/ioctl_linux.c | 219 +++++++++--------- drivers/staging/rtl8723bs/os_dep/os_intfs.c | 14 +- 2 files changed, 116 insertions(+), 117 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 783daa30f1d7..773e4816fbc4 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -664,49 +664,49 @@ static int rtw_set_wpa_ie(struct adapter *padapter, char *pie, unsigned short ie pairwise_cipher = WPA_CIPHER_NONE; switch (group_cipher) { - case WPA_CIPHER_NONE: - padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; - break; - case WPA_CIPHER_WEP40: - padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - case WPA_CIPHER_TKIP: - padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; - break; - case WPA_CIPHER_CCMP: - padapter->securitypriv.dot118021XGrpPrivacy = _AES_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; - break; - case WPA_CIPHER_WEP104: - padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; + case WPA_CIPHER_NONE: + padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.dot118021XGrpPrivacy = _AES_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; } switch (pairwise_cipher) { - case WPA_CIPHER_NONE: - padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; - break; - case WPA_CIPHER_WEP40: - padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; - case WPA_CIPHER_TKIP: - padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; - break; - case WPA_CIPHER_CCMP: - padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; - break; - case WPA_CIPHER_WEP104: - padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; - padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; - break; + case WPA_CIPHER_NONE: + padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11EncryptionDisabled; + break; + case WPA_CIPHER_WEP40: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; + case WPA_CIPHER_TKIP: + padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption2Enabled; + break; + case WPA_CIPHER_CCMP: + padapter->securitypriv.dot11PrivacyAlgrthm = _AES_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption3Enabled; + break; + case WPA_CIPHER_WEP104: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; + padapter->securitypriv.ndisencryptstatus = Ndis802_11Encryption1Enabled; + break; } _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS); @@ -860,28 +860,27 @@ static int rtw_wx_set_mode(struct net_device *dev, struct iw_request_info *a, } switch (wrqu->mode) { - case IW_MODE_AUTO: - networkType = Ndis802_11AutoUnknown; - DBG_871X("set_mode = IW_MODE_AUTO\n"); - break; - case IW_MODE_ADHOC: - networkType = Ndis802_11IBSS; - DBG_871X("set_mode = IW_MODE_ADHOC\n"); - break; - case IW_MODE_MASTER: - networkType = Ndis802_11APMode; - DBG_871X("set_mode = IW_MODE_MASTER\n"); - /* rtw_setopmode_cmd(padapter, networkType, true); */ - break; - case IW_MODE_INFRA: - networkType = Ndis802_11Infrastructure; - DBG_871X("set_mode = IW_MODE_INFRA\n"); - break; - - default: - ret = -EINVAL; - RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode])); - goto exit; + case IW_MODE_AUTO: + networkType = Ndis802_11AutoUnknown; + DBG_871X("set_mode = IW_MODE_AUTO\n"); + break; + case IW_MODE_ADHOC: + networkType = Ndis802_11IBSS; + DBG_871X("set_mode = IW_MODE_ADHOC\n"); + break; + case IW_MODE_MASTER: + networkType = Ndis802_11APMode; + DBG_871X("set_mode = IW_MODE_MASTER\n"); + /* rtw_setopmode_cmd(padapter, networkType, true); */ + break; + case IW_MODE_INFRA: + networkType = Ndis802_11Infrastructure; + DBG_871X("set_mode = IW_MODE_INFRA\n"); + break; + default: + ret = -EINVAL; + RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("\n Mode: %s is not supported \n", iw_operation_mode[wrqu->mode])); + goto exit; } /* @@ -1342,50 +1341,50 @@ static int rtw_wx_set_scan(struct net_device *dev, struct iw_request_info *a, section = *(pos++); len -= 1; switch (section) { - case WEXT_CSCAN_SSID_SECTION: - /* DBG_871X("WEXT_CSCAN_SSID_SECTION\n"); */ - if (len < 1) { - len = 0; - break; - } + case WEXT_CSCAN_SSID_SECTION: + /* DBG_871X("WEXT_CSCAN_SSID_SECTION\n"); */ + if (len < 1) { + len = 0; + break; + } - sec_len = *(pos++); len -= 1; + sec_len = *(pos++); len -= 1; - if (sec_len > 0 && sec_len <= len) { - ssid[ssid_index].SsidLength = sec_len; - memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); - /* DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */ - /* , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); */ - ssid_index++; - } + if (sec_len > 0 && sec_len <= len) { + ssid[ssid_index].SsidLength = sec_len; + memcpy(ssid[ssid_index].Ssid, pos, ssid[ssid_index].SsidLength); + /* DBG_871X("%s COMBO_SCAN with specific ssid:%s, %d\n", __func__ */ + /* , ssid[ssid_index].Ssid, ssid[ssid_index].SsidLength); */ + ssid_index++; + } - pos += sec_len; len -= sec_len; - break; + pos += sec_len; len -= sec_len; + break; - case WEXT_CSCAN_CHANNEL_SECTION: - /* DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); */ - pos += 1; len -= 1; - break; - case WEXT_CSCAN_ACTV_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */ - pos += 2; len -= 2; - break; - case WEXT_CSCAN_PASV_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */ - pos += 2; len -= 2; - break; - case WEXT_CSCAN_HOME_DWELL_SECTION: - /* DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */ - pos += 2; len -= 2; - break; - case WEXT_CSCAN_TYPE_SECTION: - /* DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); */ - pos += 1; len -= 1; - break; - default: - /* DBG_871X("Unknown CSCAN section %c\n", section); */ - len = 0; /* stop parsing */ + case WEXT_CSCAN_CHANNEL_SECTION: + /* DBG_871X("WEXT_CSCAN_CHANNEL_SECTION\n"); */ + pos += 1; len -= 1; + break; + case WEXT_CSCAN_ACTV_DWELL_SECTION: + /* DBG_871X("WEXT_CSCAN_ACTV_DWELL_SECTION\n"); */ + pos += 2; len -= 2; + break; + case WEXT_CSCAN_PASV_DWELL_SECTION: + /* DBG_871X("WEXT_CSCAN_PASV_DWELL_SECTION\n"); */ + pos += 2; len -= 2; + break; + case WEXT_CSCAN_HOME_DWELL_SECTION: + /* DBG_871X("WEXT_CSCAN_HOME_DWELL_SECTION\n"); */ + pos += 2; len -= 2; + break; + case WEXT_CSCAN_TYPE_SECTION: + /* DBG_871X("WEXT_CSCAN_TYPE_SECTION\n"); */ + pos += 1; len -= 1; + break; + default: + /* DBG_871X("Unknown CSCAN section %c\n", section); */ + len = 0; /* stop parsing */ } /* DBG_871X("len:%d\n", len); */ @@ -1917,15 +1916,15 @@ static int rtw_wx_set_enc(struct net_device *dev, DBG_871X("(keyindex_provided == 1), keyid =%d, key_len =%d\n", key, padapter->securitypriv.dot11DefKeylen[key]); switch (padapter->securitypriv.dot11DefKeylen[key]) { - case 5: - padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; - break; - case 13: - padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; - break; - default: - padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; - break; + case 5: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_; + break; + case 13: + padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_; + break; + default: + padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_; + break; } goto exit; diff --git a/drivers/staging/rtl8723bs/os_dep/os_intfs.c b/drivers/staging/rtl8723bs/os_dep/os_intfs.c index ed8212b7deb4..b62fe9238e6d 100644 --- a/drivers/staging/rtl8723bs/os_dep/os_intfs.c +++ b/drivers/staging/rtl8723bs/os_dep/os_intfs.c @@ -400,17 +400,17 @@ u16 rtw_recv_select_queue(struct sk_buff *skb) memcpy(ð_type, pdata + (ETH_ALEN << 1), 2); switch (be16_to_cpu(eth_type)) { - case ETH_P_IP: + case ETH_P_IP: - piphdr = (struct iphdr *)(pdata + ETH_HLEN); + piphdr = (struct iphdr *)(pdata + ETH_HLEN); - dscp = piphdr->tos & 0xfc; + dscp = piphdr->tos & 0xfc; - priority = dscp >> 5; + priority = dscp >> 5; - break; - default: - priority = 0; + break; + default: + priority = 0; } return rtw_1d_to_queue[priority]; -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:06 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:06 -0600 Subject: [PATCH 08/10] staging: rtl8723bs: clean up logical continuations In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-8-ross.schm.dev@gmail.com> Move operators to fix coding style issues and clear checkpatch checks. CHECK: Logical continuations should be on the previous line Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 41 +++++++------------ drivers/staging/rtl8723bs/core/rtw_recv.c | 27 ++++++------ .../staging/rtl8723bs/core/rtw_wlan_util.c | 6 +-- drivers/staging/rtl8723bs/core/rtw_xmit.c | 6 +-- 4 files changed, 34 insertions(+), 46 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 90e222a9c93b..5b05d1eaa328 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -451,9 +451,8 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a hal_btcoex_LpsNotify(padapter, ps_mode); } } else { - if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) - || ((hal_btcoex_IsBtControlLps(padapter)) - && (hal_btcoex_IsLpsOn(padapter))) + if ((PS_RDY_CHECK(padapter) && check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) || + ((hal_btcoex_IsBtControlLps(padapter)) && (hal_btcoex_IsLpsOn(padapter))) ) { u8 pslv; @@ -472,8 +471,8 @@ void rtw_set_ps_mode(struct adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_a if (pwrpriv->alives == 0) pslv = PS_STATE_S0; - if (!(hal_btcoex_IsBtDisabled(padapter)) - && (hal_btcoex_IsBtControlLps(padapter))) { + if (!(hal_btcoex_IsBtDisabled(padapter)) && + (hal_btcoex_IsBtControlLps(padapter))) { u8 val8; val8 = hal_btcoex_LpsVal(padapter); @@ -688,9 +687,9 @@ void LPS_Leave_check(struct adapter *padapter) while (1) { mutex_lock(&pwrpriv->lock); - if (padapter->bSurpriseRemoved - || !(padapter->hw_init_completed) - || (pwrpriv->pwr_mode == PS_MODE_ACTIVE)) + if (padapter->bSurpriseRemoved || + !(padapter->hw_init_completed) || + (pwrpriv->pwr_mode == PS_MODE_ACTIVE)) bReady = true; mutex_unlock(&pwrpriv->lock); @@ -897,8 +896,7 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task) pwrctrl = adapter_to_pwrctl(padapter); pslv = PS_STATE_S0; - if (!(hal_btcoex_IsBtDisabled(padapter)) - && hal_btcoex_IsBtControlLps(padapter)) { + if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) { u8 val8; val8 = hal_btcoex_LpsVal(padapter); @@ -910,8 +908,7 @@ void rtw_unregister_task_alive(struct adapter *padapter, u32 task) unregister_task_alive(pwrctrl, task); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) - && pwrctrl->bFwCurrentInPSMode) { + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ("%s: cpwm = 0x%02x alives = 0x%08x\n", __func__, pwrctrl->cpwm, pwrctrl->alives)); @@ -1038,8 +1035,7 @@ void rtw_unregister_tx_alive(struct adapter *padapter) pwrctrl = adapter_to_pwrctl(padapter); pslv = PS_STATE_S0; - if (!(hal_btcoex_IsBtDisabled(padapter)) - && hal_btcoex_IsBtControlLps(padapter)) { + if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) { u8 val8; val8 = hal_btcoex_LpsVal(padapter); @@ -1051,8 +1047,7 @@ void rtw_unregister_tx_alive(struct adapter *padapter) unregister_task_alive(pwrctrl, XMIT_ALIVE); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) - && pwrctrl->bFwCurrentInPSMode) { + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_, ("%s: cpwm = 0x%02x alives = 0x%08x\n", __func__, pwrctrl->cpwm, pwrctrl->alives)); @@ -1080,8 +1075,7 @@ void rtw_unregister_cmd_alive(struct adapter *padapter) pwrctrl = adapter_to_pwrctl(padapter); pslv = PS_STATE_S0; - if (!(hal_btcoex_IsBtDisabled(padapter)) - && hal_btcoex_IsBtControlLps(padapter)) { + if (!(hal_btcoex_IsBtDisabled(padapter)) && hal_btcoex_IsBtControlLps(padapter)) { u8 val8; val8 = hal_btcoex_LpsVal(padapter); @@ -1093,8 +1087,7 @@ void rtw_unregister_cmd_alive(struct adapter *padapter) unregister_task_alive(pwrctrl, CMD_ALIVE); - if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) - && pwrctrl->bFwCurrentInPSMode) { + if ((pwrctrl->pwr_mode != PS_MODE_ACTIVE) && pwrctrl->bFwCurrentInPSMode) { RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_info_, ("%s: cpwm = 0x%02x alives = 0x%08x\n", __func__, pwrctrl->cpwm, pwrctrl->alives)); @@ -1226,8 +1219,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal if (!(pwrpriv->bInternalAutoSuspend) && pwrpriv->bInSuspend) { DBG_871X("%s wait bInSuspend...\n", __func__); - while (pwrpriv->bInSuspend - && jiffies_to_msecs(jiffies - start) <= 3000 + while (pwrpriv->bInSuspend && jiffies_to_msecs(jiffies - start) <= 3000 ) { mdelay(10); } @@ -1267,10 +1259,7 @@ int _rtw_pwr_wakeup(struct adapter *padapter, u32 ips_deffer_ms, const char *cal } /* TODO: the following checking need to be merged... */ - if (padapter->bDriverStopped - || !padapter->bup - || !padapter->hw_init_completed - ) { + if (padapter->bDriverStopped || !padapter->bup || !padapter->hw_init_completed) { DBG_8192C("%s: bDriverStopped =%d, bup =%d, hw_init_completed =%u\n" , caller , padapter->bDriverStopped diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index e1528b51c17e..43e67e48d2df 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -499,9 +499,8 @@ union recv_frame *decryptor(struct adapter *padapter, union recv_frame *precv_fr default: break; } - } else if (prxattrib->bdecrypted == 1 - && prxattrib->encrypt > 0 - && (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_) + } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 && + (psecuritypriv->busetkipkey == 1 || prxattrib->encrypt != _TKIP_) ) { DBG_COUNTER(padapter->rx_logs.core_rx_post_decrypt_hw); @@ -874,9 +873,9 @@ sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, u8 *myhwaddr = myid(&adapter->eeprompriv); sint bmcast = IS_MCAST(pattrib->dst); - if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) - && (check_fwstate(pmlmepriv, _FW_LINKED) == true - || check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) + if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) && + (check_fwstate(pmlmepriv, _FW_LINKED) == true || + check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) ) { /* filter packets that SA is myself or multicast or broadcast */ @@ -1226,8 +1225,8 @@ sint validate_recv_mgnt_frame(struct adapter *padapter, union recv_frame *precv_ else if (GetFrameSubType(precv_frame->u.hdr.rx_data) == WIFI_PROBERSP) { if (!memcmp(padapter->eeprompriv.mac_addr, GetAddr1Ptr(precv_frame->u.hdr.rx_data), ETH_ALEN)) psta->sta_stats.rx_probersp_pkts++; - else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) - || is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))) + else if (is_broadcast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data)) || + is_multicast_mac_addr(GetAddr1Ptr(precv_frame->u.hdr.rx_data))) psta->sta_stats.rx_probersp_bm_pkts++; else psta->sta_stats.rx_probersp_uo_pkts++; @@ -1388,8 +1387,8 @@ static sint validate_80211w_mgmt(struct adapter *adapter, union recv_frame *prec subtype = GetFrameSubType(ptr); /* bit(7)~bit(2) */ /* only support station mode */ - if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) - && adapter->securitypriv.binstallBIPkey == true) { + if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) && check_fwstate(pmlmepriv, _FW_LINKED) && + adapter->securitypriv.binstallBIPkey == true) { /* unicast management frame decrypt */ if (pattrib->privacy && !(IS_MCAST(GetAddr1Ptr(ptr))) && (subtype == WIFI_DEAUTH || subtype == WIFI_DISASSOC || subtype == WIFI_ACTION)) { @@ -2601,15 +2600,15 @@ static void rtw_signal_stat_timer_hdl(struct timer_list *t) } if (num_signal_strength == 0) { - if (rtw_get_on_cur_ch_time(adapter) == 0 - || jiffies_to_msecs(jiffies - rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval + if (rtw_get_on_cur_ch_time(adapter) == 0 || + jiffies_to_msecs(jiffies - rtw_get_on_cur_ch_time(adapter)) < 2 * adapter->mlmeextpriv.mlmext_info.bcn_interval ) { goto set_timer; } } - if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == true - || check_fwstate(&adapter->mlmepriv, _FW_LINKED) == false + if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) == true || + check_fwstate(&adapter->mlmepriv, _FW_LINKED) == false ) { goto set_timer; } diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index a6176e86f370..45e5f06f0004 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -1584,9 +1584,9 @@ unsigned char check_assoc_AP(u8 *pframe, uint len) if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) || (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) { DBG_871X("link to Artheros AP\n"); return HT_IOT_PEER_ATHEROS; - } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) - || (!memcmp(pIE->data, BROADCOM_OUI2, 3)) - || (!memcmp(pIE->data, BROADCOM_OUI3, 3))) { + } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) || + (!memcmp(pIE->data, BROADCOM_OUI2, 3)) || + (!memcmp(pIE->data, BROADCOM_OUI3, 3))) { DBG_871X("link to Broadcom AP\n"); return HT_IOT_PEER_BROADCOM; } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) { diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index b69998c5c07e..6582f2d7c383 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -2173,9 +2173,9 @@ inline bool xmitframe_hiq_filter(struct xmit_frame *xmitframe) if (registry->hiq_filter == RTW_HIQ_FILTER_ALLOW_SPECIAL) { struct pkt_attrib *attrib = &xmitframe->attrib; - if (attrib->ether_type == 0x0806 - || attrib->ether_type == 0x888e - || attrib->dhcp_pkt + if (attrib->ether_type == 0x0806 || + attrib->ether_type == 0x888e || + attrib->dhcp_pkt ) { DBG_871X(FUNC_ADPT_FMT" ether_type:0x%04x%s\n", FUNC_ADPT_ARG(xmitframe->padapter) , attrib->ether_type, attrib->dhcp_pkt?" DHCP":""); -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:02 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:02 -0600 Subject: [PATCH 04/10] staging: rtl8723bs: clean up open ended lines In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-4-ross.schm.dev@gmail.com> Move declarations to fix coding style issues and clear checkpatch checks. CHECK: Lines should not end with a '(' Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/core/rtw_efuse.c | 44 +-- .../staging/rtl8723bs/core/rtw_ieee80211.c | 13 +- .../staging/rtl8723bs/core/rtw_ioctl_set.c | 10 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 16 +- drivers/staging/rtl8723bs/core/rtw_pwrctrl.c | 7 +- drivers/staging/rtl8723bs/core/rtw_recv.c | 38 +-- drivers/staging/rtl8723bs/core/rtw_security.c | 261 ++++++------------ drivers/staging/rtl8723bs/core/rtw_sta_mgt.c | 42 ++- drivers/staging/rtl8723bs/core/rtw_xmit.c | 17 +- 9 files changed, 147 insertions(+), 301 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_efuse.c b/drivers/staging/rtl8723bs/core/rtw_efuse.c index 8794638468e6..32ca10f01413 100644 --- a/drivers/staging/rtl8723bs/core/rtw_efuse.c +++ b/drivers/staging/rtl8723bs/core/rtw_efuse.c @@ -303,12 +303,7 @@ bool bPseudoTest) } /* 11/16/2008 MH Write one byte to reald Efuse. */ -u8 -efuse_OneByteWrite( -struct adapter *padapter, -u16 addr, -u8 data, -bool bPseudoTest) +u8 efuse_OneByteWrite(struct adapter *padapter, u16 addr, u8 data, bool bPseudoTest) { u8 tmpidx = 0; u8 bResult = false; @@ -456,12 +451,7 @@ Efuse_ReadAllMap( u8 efuseType, u8 *Efuse, bool bPseudoTest); -void -Efuse_ReadAllMap( - struct adapter *padapter, - u8 efuseType, - u8 *Efuse, - bool bPseudoTest) +void Efuse_ReadAllMap(struct adapter *padapter, u8 efuseType, u8 *Efuse, bool bPseudoTest) { u16 mapLen = 0; @@ -492,11 +482,7 @@ Efuse_ReadAllMap( * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ -static void -efuse_ShadowRead1Byte( -struct adapter *padapter, -u16 Offset, - u8 *Value) +static void efuse_ShadowRead1Byte(struct adapter *padapter, u16 Offset, u8 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); @@ -505,11 +491,7 @@ u16 Offset, } /* EFUSE_ShadowRead1Byte */ /* Read Two Bytes */ -static void -efuse_ShadowRead2Byte( -struct adapter *padapter, -u16 Offset, - u16 *Value) +static void efuse_ShadowRead2Byte(struct adapter *padapter, u16 Offset, u16 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); @@ -519,11 +501,7 @@ u16 Offset, } /* EFUSE_ShadowRead2Byte */ /* Read Four Bytes */ -static void -efuse_ShadowRead4Byte( -struct adapter *padapter, -u16 Offset, - u32 *Value) +static void efuse_ShadowRead4Byte(struct adapter *padapter, u16 Offset, u32 *Value) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); @@ -550,10 +528,7 @@ u16 Offset, * 11/13/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ -void EFUSE_ShadowMapUpdate( - struct adapter *padapter, - u8 efuseType, - bool bPseudoTest) +void EFUSE_ShadowMapUpdate(struct adapter *padapter, u8 efuseType, bool bPseudoTest) { struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter); u16 mapLen = 0; @@ -586,12 +561,7 @@ void EFUSE_ShadowMapUpdate( * 11/12/2008 MHC Create Version 0. * *---------------------------------------------------------------------------*/ -void -EFUSE_ShadowRead( - struct adapter *padapter, - u8 Type, - u16 Offset, - u32 *Value) +void EFUSE_ShadowRead(struct adapter *padapter, u8 Type, u16 Offset, u32 *Value) { if (Type == 1) efuse_ShadowRead1Byte(padapter, Offset, (u8 *)Value); diff --git a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c index 066dd9cbb60d..8d61be5bd250 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723bs/core/rtw_ieee80211.c @@ -119,14 +119,11 @@ u8 *rtw_set_fixed_ie(unsigned char *pbuf, unsigned int len, unsigned char *sourc } /* rtw_set_ie will update frame length */ -u8 *rtw_set_ie -( - u8 *pbuf, - sint index, - uint len, - u8 *source, - uint *frlen /* frame length */ -) +u8 *rtw_set_ie(u8 *pbuf, + sint index, + uint len, + u8 *source, + uint *frlen) /* frame length */ { *pbuf = (u8)index; diff --git a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c index e0bab0a71f00..3adeca6f20ec 100644 --- a/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8723bs/core/rtw_ioctl_set.c @@ -657,12 +657,10 @@ u16 rtw_get_cur_max_rate(struct adapter *adapter) if (IsSupportedHT(psta->wireless_mode)) { rtw_hal_get_hwreg(adapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type)); - max_rate = rtw_mcs_rate( - rf_type, - ((psta->bw_mode == CHANNEL_WIDTH_40)?1:0), - short_GI, - psta->htpriv.ht_cap.mcs.rx_mask - ); + max_rate = rtw_mcs_rate(rf_type, + ((psta->bw_mode == CHANNEL_WIDTH_40)?1:0), + short_GI, + psta->htpriv.ht_cap.mcs.rx_mask); } else { while ((pcur_bss->SupportedRates[i] != 0) && (pcur_bss->SupportedRates[i] != 0xFF)) { rate = pcur_bss->SupportedRates[i]&0x7F; diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index 1a6cae5f9895..e0b0dd226144 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -2487,11 +2487,9 @@ void issue_beacon(struct adapter *padapter, int timeout_ms) int len_diff; memcpy(pframe, cur_network->IEs, cur_network->IELength); - len_diff = update_hidden_ssid( - pframe+_BEACON_IE_OFFSET_ - , cur_network->IELength-_BEACON_IE_OFFSET_ - , pmlmeinfo->hidden_ssid_mode - ); + len_diff = update_hidden_ssid(pframe+_BEACON_IE_OFFSET_, + cur_network->IELength-_BEACON_IE_OFFSET_, + pmlmeinfo->hidden_ssid_mode); pframe += (cur_network->IELength+len_diff); pattrib->pktlen += (cur_network->IELength+len_diff); } @@ -6584,11 +6582,9 @@ u8 set_tx_beacon_cmd(struct adapter *padapter) memcpy(&(ptxBeacon_parm->network), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); - len_diff = update_hidden_ssid( - ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_ - , ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_ - , pmlmeinfo->hidden_ssid_mode - ); + len_diff = update_hidden_ssid(ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_, + ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_, + pmlmeinfo->hidden_ssid_mode); ptxBeacon_parm->network.IELength += len_diff; init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon)); diff --git a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c index 8fe1d7429760..90e222a9c93b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8723bs/core/rtw_pwrctrl.c @@ -672,8 +672,7 @@ void LeaveAllPowerSaveMode(struct adapter *Adapter) } } -void LPS_Leave_check( - struct adapter *padapter) +void LPS_Leave_check(struct adapter *padapter) { struct pwrctrl_priv *pwrpriv; unsigned long start_time; @@ -714,9 +713,7 @@ void LPS_Leave_check( * * using to update cpwn of drv; and drv willl make a decision to up or down pwr level */ -void cpwm_int_hdl( - struct adapter *padapter, - struct reportpwrstate_parm *preportpwrstate) +void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportpwrstate) { struct pwrctrl_priv *pwrpriv; diff --git a/drivers/staging/rtl8723bs/core/rtw_recv.c b/drivers/staging/rtl8723bs/core/rtw_recv.c index c854aa3ff992..e1528b51c17e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_recv.c +++ b/drivers/staging/rtl8723bs/core/rtw_recv.c @@ -765,16 +765,10 @@ void count_rx_stats(struct adapter *padapter, union recv_frame *prframe, struct traffic_check_for_leave_lps(padapter, false, 0); } -sint sta2sta_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta -); -sint sta2sta_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta -) +sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta); +sint sta2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta) { u8 *ptr = precv_frame->u.hdr.rx_data; sint ret = _SUCCESS; @@ -866,14 +860,10 @@ sint sta2sta_data_frame( return ret; } -sint ap2sta_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta); -sint ap2sta_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta) +sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta); +sint ap2sta_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta) { u8 *ptr = precv_frame->u.hdr.rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; @@ -1015,14 +1005,10 @@ sint ap2sta_data_frame( return ret; } -sint sta2ap_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta); -sint sta2ap_data_frame( - struct adapter *adapter, - union recv_frame *precv_frame, - struct sta_info **psta) +sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta); +sint sta2ap_data_frame(struct adapter *adapter, union recv_frame *precv_frame, + struct sta_info **psta) { u8 *ptr = precv_frame->u.hdr.rx_data; struct rx_pkt_attrib *pattrib = &precv_frame->u.hdr.attrib; diff --git a/drivers/staging/rtl8723bs/core/rtw_security.c b/drivers/staging/rtl8723bs/core/rtw_security.c index 41b80e433cc2..33f5d3c5ac36 100644 --- a/drivers/staging/rtl8723bs/core/rtw_security.c +++ b/drivers/staging/rtl8723bs/core/rtw_security.c @@ -140,12 +140,7 @@ static u32 arcfour_byte(struct arc4context *parc4ctx) return state[(sx + sy) & 0xff]; } -static void arcfour_encrypt( - struct arc4context *parc4ctx, - u8 *dest, - u8 *src, - u32 len -) +static void arcfour_encrypt(struct arc4context *parc4ctx, u8 *dest, u8 *src, u32 len) { u32 i; @@ -882,36 +877,28 @@ u32 rtw_tkip_decrypt(struct adapter *padapter, u8 *precvframe) /*****************************/ static void bitwise_xor(u8 *ina, u8 *inb, u8 *out); -static void construct_mic_iv( - u8 *mic_header1, - sint qc_exists, - sint a4_exists, - u8 *mpdu, - uint payload_length, - u8 *pn_vector, - uint frtype -);/* add for CONFIG_IEEE80211W, none 11w also can use */ -static void construct_mic_header1( - u8 *mic_header1, - sint header_length, - u8 *mpdu, - uint frtype -);/* add for CONFIG_IEEE80211W, none 11w also can use */ -static void construct_mic_header2( - u8 *mic_header2, - u8 *mpdu, - sint a4_exists, - sint qc_exists -); -static void construct_ctr_preload( - u8 *ctr_preload, - sint a4_exists, - sint qc_exists, - u8 *mpdu, - u8 *pn_vector, - sint c, - uint frtype -);/* add for CONFIG_IEEE80211W, none 11w also can use */ +static void construct_mic_iv(u8 *mic_header1, + sint qc_exists, + sint a4_exists, + u8 *mpdu, + uint payload_length, + u8 *pn_vector, + uint frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ +static void construct_mic_header1(u8 *mic_header1, + sint header_length, + u8 *mpdu, + uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ +static void construct_mic_header2(u8 *mic_header2, + u8 *mpdu, + sint a4_exists, + sint qc_exists); +static void construct_ctr_preload(u8 *ctr_preload, + sint a4_exists, + sint qc_exists, + u8 *mpdu, + u8 *pn_vector, + sint c, + uint frtype); /* for CONFIG_IEEE80211W, none 11w also can use */ static void xor_128(u8 *a, u8 *b, u8 *out); static void xor_32(u8 *a, u8 *b, u8 *out); static u8 sbox(u8 a); @@ -1103,15 +1090,13 @@ static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext) /* Baron think the function is construct CCM */ /* nonce */ /************************************************/ -static void construct_mic_iv( - u8 *mic_iv, - sint qc_exists, - sint a4_exists, - u8 *mpdu, - uint payload_length, - u8 *pn_vector, - uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ -) +static void construct_mic_iv(u8 *mic_iv, + sint qc_exists, + sint a4_exists, + u8 *mpdu, + uint payload_length, + u8 *pn_vector, + uint frtype) /* add for CONFIG_IEEE80211W, none 11w also can use */ { sint i; @@ -1149,12 +1134,10 @@ static void construct_mic_iv( /* header fields. */ /* Build AAD SC, A1, A2 */ /************************************************/ -static void construct_mic_header1( - u8 *mic_header1, - sint header_length, - u8 *mpdu, - uint frtype/* add for CONFIG_IEEE80211W, none 11w also can use */ -) +static void construct_mic_header1(u8 *mic_header1, + sint header_length, + u8 *mpdu, + uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */ { mic_header1[0] = (u8)((header_length - 2) / 256); mic_header1[1] = (u8)((header_length - 2) % 256); @@ -1185,12 +1168,10 @@ static void construct_mic_header1( /* Builds the last MIC header block from */ /* header fields. */ /************************************************/ -static void construct_mic_header2( - u8 *mic_header2, - u8 *mpdu, - sint a4_exists, - sint qc_exists -) +static void construct_mic_header2(u8 *mic_header2, + u8 *mpdu, + sint a4_exists, + sint qc_exists) { sint i; @@ -1233,15 +1214,13 @@ static void construct_mic_header2( /* Baron think the function is construct CCM */ /* nonce */ /************************************************/ -static void construct_ctr_preload( - u8 *ctr_preload, - sint a4_exists, - sint qc_exists, - u8 *mpdu, - u8 *pn_vector, - sint c, - uint frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ -) +static void construct_ctr_preload(u8 *ctr_preload, + sint a4_exists, + sint qc_exists, + u8 *mpdu, + u8 *pn_vector, + sint c, + uint frtype) /* for CONFIG_IEEE80211W, none 11w also can use */ { sint i = 0; @@ -1347,28 +1326,23 @@ static sint aes_cipher(u8 *key, uint hdrlen, pn_vector[4] = pframe[hdrlen+6]; pn_vector[5] = pframe[hdrlen+7]; - construct_mic_iv( - mic_iv, - qc_exists, - a4_exists, - pframe, /* message, */ - plen, - pn_vector, - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); - - construct_mic_header1( - mic_header1, - hdrlen, - pframe, /* message */ - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); - construct_mic_header2( - mic_header2, - pframe, /* message, */ - a4_exists, - qc_exists - ); + construct_mic_iv(mic_iv, + qc_exists, + a4_exists, + pframe, /* message, */ + plen, + pn_vector, + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + construct_mic_header1(mic_header1, + hdrlen, + pframe, /* message */ + frtype); /* add for CONFIG_IEEE80211W, none 11w also can use */ + + construct_mic_header2(mic_header2, + pframe, /* message, */ + a4_exists, + qc_exists); payload_remainder = plen % 16; num_blocks = plen / 16; @@ -1410,15 +1384,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, payload_index = hdrlen + 8; for (i = 0; i < num_blocks; i++) { - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - pframe, /* message, */ - pn_vector, - i+1, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */ + pn_vector, i+1, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, &pframe[payload_index], chain_buffer); for (j = 0; j < 16; j++) @@ -1428,15 +1396,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ /* encrypt it and copy the unpadded part back */ - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - pframe, /* message, */ - pn_vector, - num_blocks+1, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */ + pn_vector, num_blocks+1, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; @@ -1450,15 +1412,9 @@ static sint aes_cipher(u8 *key, uint hdrlen, } /* Encrypt the MIC */ - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - pframe, /* message, */ - pn_vector, - 0, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, /* message, */ + pn_vector, 0, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; @@ -1613,15 +1569,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ /* encrypt it and copy the unpadded part back */ - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - pframe, - pn_vector, - num_blocks+1, - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe, pn_vector, + num_blocks+1, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; @@ -1645,28 +1595,12 @@ static sint aes_decipher(u8 *key, uint hdrlen, pn_vector[4] = pframe[hdrlen+6]; pn_vector[5] = pframe[hdrlen+7]; - construct_mic_iv( - mic_iv, - qc_exists, - a4_exists, - message, - plen-8, - pn_vector, - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); - - construct_mic_header1( - mic_header1, - hdrlen, - message, - frtype /* add for CONFIG_IEEE80211W, none 11w also can use */ - ); - construct_mic_header2( - mic_header2, - message, - a4_exists, - qc_exists - ); + construct_mic_iv(mic_iv, qc_exists, a4_exists, message, plen-8, pn_vector, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ + + construct_mic_header1(mic_header1, hdrlen, message, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_mic_header2(mic_header2, message, a4_exists, qc_exists); payload_remainder = (plen-8) % 16; num_blocks = (plen-8) / 16; @@ -1708,15 +1642,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, payload_index = hdrlen + 8; for (i = 0; i < num_blocks; i++) { - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - message, - pn_vector, - i+1, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, i+1, + frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ aes128k128d(key, ctr_preload, aes_out); bitwise_xor(aes_out, &message[payload_index], chain_buffer); for (j = 0; j < 16; j++) @@ -1726,15 +1654,9 @@ static sint aes_decipher(u8 *key, uint hdrlen, if (payload_remainder > 0) { /* If there is a short final block, then pad it,*/ /* encrypt it and copy the unpadded part back */ - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - message, - pn_vector, - num_blocks+1, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, + num_blocks+1, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; @@ -1748,15 +1670,8 @@ static sint aes_decipher(u8 *key, uint hdrlen, } /* Encrypt the MIC */ - construct_ctr_preload( - ctr_preload, - a4_exists, - qc_exists, - message, - pn_vector, - 0, - frtype - ); /* add for CONFIG_IEEE80211W, none 11w also can use */ + construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message, pn_vector, 0, frtype); + /* add for CONFIG_IEEE80211W, none 11w also can use */ for (j = 0; j < 16; j++) padded_buffer[j] = 0x00; diff --git a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c index 6e9785c21cf8..f0dd4da82bf3 100644 --- a/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c +++ b/drivers/staging/rtl8723bs/core/rtw_sta_mgt.c @@ -242,18 +242,15 @@ struct sta_info *rtw_alloc_stainfo(struct sta_priv *pstapriv, u8 *hwaddr) for (i = 0; i < 16; i++) memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2); - RT_TRACE( - _module_rtl871x_sta_mgt_c_, - _drv_info_, ( - "alloc number_%d stainfo with hwaddr = %x %x %x %x %x %x \n", - pstapriv->asoc_sta_count, - hwaddr[0], - hwaddr[1], - hwaddr[2], - hwaddr[3], - hwaddr[4], - hwaddr[5] - ) + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_, + ("alloc number_%d stainfo with hwaddr = %x %x %x %x %x %x \n", + pstapriv->asoc_sta_count, + hwaddr[0], + hwaddr[1], + hwaddr[2], + hwaddr[3], + hwaddr[4], + hwaddr[5]) ); init_addba_retry_timer(pstapriv->padapter, psta); @@ -366,18 +363,15 @@ u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta) spin_unlock_bh(&pxmitpriv->lock); list_del_init(&psta->hash_list); - RT_TRACE( - _module_rtl871x_sta_mgt_c_, - _drv_err_, ( - "\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", - pstapriv->asoc_sta_count, - psta->hwaddr[0], - psta->hwaddr[1], - psta->hwaddr[2], - psta->hwaddr[3], - psta->hwaddr[4], - psta->hwaddr[5] - ) + RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, + ("\n free number_%d stainfo with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", + pstapriv->asoc_sta_count, + psta->hwaddr[0], + psta->hwaddr[1], + psta->hwaddr[2], + psta->hwaddr[3], + psta->hwaddr[4], + psta->hwaddr[5]) ); pstapriv->asoc_sta_count--; diff --git a/drivers/staging/rtl8723bs/core/rtw_xmit.c b/drivers/staging/rtl8723bs/core/rtw_xmit.c index 391bc666f7a6..b69998c5c07e 100644 --- a/drivers/staging/rtl8723bs/core/rtw_xmit.c +++ b/drivers/staging/rtl8723bs/core/rtw_xmit.c @@ -2586,9 +2586,7 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst spin_unlock_bh(&pxmitpriv->lock); } -void enqueue_pending_xmitbuf( - struct xmit_priv *pxmitpriv, - struct xmit_buf *pxmitbuf) +void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { struct __queue *pqueue; struct adapter *pri_adapter = pxmitpriv->adapter; @@ -2603,9 +2601,7 @@ void enqueue_pending_xmitbuf( complete(&pri_adapter->xmitpriv.xmit_comp); } -void enqueue_pending_xmitbuf_to_head( - struct xmit_priv *pxmitpriv, - struct xmit_buf *pxmitbuf) +void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { struct __queue *pqueue; @@ -2617,8 +2613,7 @@ void enqueue_pending_xmitbuf_to_head( spin_unlock_bh(&pqueue->lock); } -struct xmit_buf *dequeue_pending_xmitbuf( - struct xmit_priv *pxmitpriv) +struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv) { struct xmit_buf *pxmitbuf; struct __queue *pqueue; @@ -2642,8 +2637,7 @@ struct xmit_buf *dequeue_pending_xmitbuf( return pxmitbuf; } -struct xmit_buf *dequeue_pending_xmitbuf_under_survey( - struct xmit_priv *pxmitpriv) +struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv) { struct xmit_buf *pxmitbuf; struct __queue *pqueue; @@ -2683,8 +2677,7 @@ struct xmit_buf *dequeue_pending_xmitbuf_under_survey( return pxmitbuf; } -sint check_pending_xmitbuf( - struct xmit_priv *pxmitpriv) +sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv) { struct __queue *pqueue; sint ret = false; -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:07 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:07 -0600 Subject: [PATCH 09/10] staging: rtl8723bs: clean up pointer locations In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-9-ross.schm.dev@gmail.com> Move pointer locations to fix coding style issues and clear checkpatch errors. ERROR: "foo * bar" should be "foo *bar" Signed-off-by: Ross Schmidt --- drivers/staging/rtl8723bs/include/rtw_io.h | 2 +- drivers/staging/rtl8723bs/include/rtw_mlme.h | 14 +++++++------- drivers/staging/rtl8723bs/include/rtw_mp.h | 10 +++++----- drivers/staging/rtl8723bs/include/rtw_pwrctrl.h | 6 +++--- drivers/staging/rtl8723bs/include/rtw_recv.h | 4 ++-- drivers/staging/rtl8723bs/include/rtw_security.h | 12 ++++++------ drivers/staging/rtl8723bs/include/rtw_xmit.h | 8 ++++---- drivers/staging/rtl8723bs/include/sta_info.h | 2 +- drivers/staging/rtl8723bs/include/wifi.h | 10 +++++----- drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c | 14 +++++++------- drivers/staging/rtl8723bs/os_dep/ioctl_linux.c | 8 ++++---- drivers/staging/rtl8723bs/os_dep/recv_linux.c | 10 +++++----- 12 files changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/staging/rtl8723bs/include/rtw_io.h b/drivers/staging/rtl8723bs/include/rtw_io.h index 2581b5165d1b..b7076b590d84 100644 --- a/drivers/staging/rtl8723bs/include/rtw_io.h +++ b/drivers/staging/rtl8723bs/include/rtw_io.h @@ -345,7 +345,7 @@ extern void free_io_queue(struct adapter *adapter); extern void async_bus_io(struct io_queue *pio_q); extern void bus_sync_io(struct io_queue *pio_q); extern u32 _ioreq2rwmem(struct io_queue *pio_q); -extern void dev_power_down(struct adapter * Adapter, u8 bpwrup); +extern void dev_power_down(struct adapter *Adapter, u8 bpwrup); #define PlatformEFIOWrite1Byte(_a, _b, _c) \ rtw_write8(_a, _b, _c) diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme.h b/drivers/staging/rtl8723bs/include/rtw_mlme.h index 07efb74831eb..ea0dd156051e 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme.h @@ -559,15 +559,15 @@ static inline void set_scanned_network_val(struct mlme_priv *pmlmepriv, sint val extern u16 rtw_get_capability(struct wlan_bssid_ex *bss); extern void rtw_update_scanned_network(struct adapter *adapter, struct wlan_bssid_ex *target); -extern void rtw_disconnect_hdl_under_linked(struct adapter * adapter, struct sta_info *psta, u8 free_assoc); +extern void rtw_disconnect_hdl_under_linked(struct adapter *adapter, struct sta_info *psta, u8 free_assoc); extern void rtw_generate_random_ibss(u8 *pibss); -extern struct wlan_network* rtw_find_network(struct __queue *scanned_queue, u8 *addr); -extern struct wlan_network* rtw_get_oldest_wlan_network(struct __queue *scanned_queue); +extern struct wlan_network *rtw_find_network(struct __queue *scanned_queue, u8 *addr); +extern struct wlan_network *rtw_get_oldest_wlan_network(struct __queue *scanned_queue); struct wlan_network *_rtw_find_same_network(struct __queue *scanned_queue, struct wlan_network *network); -extern void rtw_free_assoc_resources(struct adapter * adapter, int lock_scanned_queue); -extern void rtw_indicate_disconnect(struct adapter * adapter); -extern void rtw_indicate_connect(struct adapter * adapter); +extern void rtw_free_assoc_resources(struct adapter *adapter, int lock_scanned_queue); +extern void rtw_indicate_disconnect(struct adapter *adapter); +extern void rtw_indicate_connect(struct adapter *adapter); void rtw_indicate_scan_done(struct adapter *padapter, bool aborted); void rtw_scan_abort(struct adapter *adapter); @@ -600,7 +600,7 @@ extern void _rtw_free_network(struct mlme_priv *pmlmepriv, struct wlan_network * extern void _rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork); -extern struct wlan_network* _rtw_find_network(struct __queue *scanned_queue, u8 *addr); +extern struct wlan_network *_rtw_find_network(struct __queue *scanned_queue, u8 *addr); extern sint rtw_if_up(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/rtw_mp.h b/drivers/staging/rtl8723bs/include/rtw_mp.h index 4d156eab029c..ab7cd51ce681 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mp.h +++ b/drivers/staging/rtl8723bs/include/rtw_mp.h @@ -31,7 +31,7 @@ struct mp_wiparam { u32 io_value; }; -typedef void(*wi_act_func)(void* padapter); +typedef void(*wi_act_func)(void *padapter); struct mp_tx { u8 stop; @@ -478,13 +478,13 @@ void Hal_SetChannel(struct adapter *padapter); void Hal_SetAntennaPathPower(struct adapter *padapter); s32 Hal_SetThermalMeter(struct adapter *padapter, u8 target_ther); s32 Hal_SetPowerTracking(struct adapter *padapter, u8 enable); -void Hal_GetPowerTracking(struct adapter *padapter, u8 * enable); +void Hal_GetPowerTracking(struct adapter *padapter, u8 *enable); void Hal_GetThermalMeter(struct adapter *padapter, u8 *value); void Hal_mpt_SwitchRfSetting(struct adapter *padapter); -void Hal_MPT_CCKTxPowerAdjust(struct adapter * Adapter, bool bInCH14); +void Hal_MPT_CCKTxPowerAdjust(struct adapter *Adapter, bool bInCH14); void Hal_MPT_CCKTxPowerAdjustbyIndex(struct adapter *padapter, bool beven); -void Hal_SetCCKTxPower(struct adapter *padapter, u8 * TxPower); -void Hal_SetOFDMTxPower(struct adapter *padapter, u8 * TxPower); +void Hal_SetCCKTxPower(struct adapter *padapter, u8 *TxPower); +void Hal_SetOFDMTxPower(struct adapter *padapter, u8 *TxPower); void Hal_TriggerRFThermalMeter(struct adapter *padapter); u8 Hal_ReadRFThermalMeter(struct adapter *padapter); void Hal_SetCCKContinuousTx(struct adapter *padapter, u8 bStart); diff --git a/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h b/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h index 3d999540e239..0987891e85ae 100644 --- a/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h +++ b/drivers/staging/rtl8723bs/include/rtw_pwrctrl.h @@ -318,7 +318,7 @@ struct pwrctrl_priv { _rtw_set_pwr_state_check_timer((pwrctl), (pwrctl)->pwr_state_check_interval) extern void rtw_init_pwrctrl_priv(struct adapter *adapter); -extern void rtw_free_pwrctrl_priv(struct adapter * adapter); +extern void rtw_free_pwrctrl_priv(struct adapter *adapter); s32 rtw_register_task_alive(struct adapter *, u32 task); void rtw_unregister_task_alive(struct adapter *, u32 task); @@ -329,8 +329,8 @@ extern void rtw_unregister_cmd_alive(struct adapter *padapter); extern void cpwm_int_hdl(struct adapter *padapter, struct reportpwrstate_parm *preportpwrstate); extern void LPS_Leave_check(struct adapter *padapter); -extern void LeaveAllPowerSaveMode(struct adapter * Adapter); -extern void LeaveAllPowerSaveModeDirect(struct adapter * Adapter); +extern void LeaveAllPowerSaveMode(struct adapter *Adapter); +extern void LeaveAllPowerSaveModeDirect(struct adapter *Adapter); void _ips_enter(struct adapter *padapter); void ips_enter(struct adapter *padapter); int _ips_leave(struct adapter *padapter); diff --git a/drivers/staging/rtl8723bs/include/rtw_recv.h b/drivers/staging/rtl8723bs/include/rtw_recv.h index 60bf00f35cae..b4aeb44d5d6e 100644 --- a/drivers/staging/rtl8723bs/include/rtw_recv.h +++ b/drivers/staging/rtl8723bs/include/rtw_recv.h @@ -450,7 +450,7 @@ static inline u8 *recvframe_put(union recv_frame *precvframe, sint sz) /* used for append sz bytes from ptr to rx_tail, update rx_tail and return the updated rx_tail to the caller */ /* after putting, rx_tail must be still larger than rx_end. */ - unsigned char * prev_rx_tail; + unsigned char *prev_rx_tail; if (precvframe == NULL) return NULL; @@ -503,7 +503,7 @@ static inline union recv_frame *rxmem_to_recvframe(u8 *rxmem) /* from any given member of recv_frame. */ /* rxmem indicates the any member/address in recv_frame */ - return (union recv_frame*)(((SIZE_PTR)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN); + return (union recv_frame *)(((SIZE_PTR)rxmem >> RXFRAME_ALIGN) << RXFRAME_ALIGN); } diff --git a/drivers/staging/rtl8723bs/include/rtw_security.h b/drivers/staging/rtl8723bs/include/rtw_security.h index 514c0799c34b..f4a3739651da 100644 --- a/drivers/staging/rtl8723bs/include/rtw_security.h +++ b/drivers/staging/rtl8723bs/include/rtw_security.h @@ -92,7 +92,7 @@ typedef struct _RT_PMKID_LIST { u8 Bssid[6]; u8 PMKID[16]; u8 SsidBuf[33]; - u8* ssid_octet; + u8 *ssid_octet; u16 ssid_length; } RT_PMKID_LIST, *PRT_PMKID_LIST; @@ -401,13 +401,13 @@ static const unsigned long K[64] = { #define MIN(x, y) (((x) < (y)) ? (x) : (y)) #endif int omac1_aes_128(u8 *key, u8 *data, size_t data_len, u8 *mac); -void rtw_secmicsetkey(struct mic_data *pmicdata, u8 * key); +void rtw_secmicsetkey(struct mic_data *pmicdata, u8 *key); void rtw_secmicappendbyte(struct mic_data *pmicdata, u8 b); -void rtw_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nBytes); -void rtw_secgetmic(struct mic_data *pmicdata, u8 * dst); +void rtw_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nBytes); +void rtw_secgetmic(struct mic_data *pmicdata, u8 *dst); void rtw_seccalctkipmic( - u8 * key, + u8 *key, u8 *header, u8 *data, u32 data_len, @@ -424,6 +424,6 @@ void rtw_wep_decrypt(struct adapter *padapter, u8 *precvframe); u32 rtw_BIP_verify(struct adapter *padapter, u8 *precvframe); void rtw_sec_restore_wep_key(struct adapter *adapter); -u8 rtw_handle_tkip_countermeasure(struct adapter * adapter, const char *caller); +u8 rtw_handle_tkip_countermeasure(struct adapter *adapter, const char *caller); #endif /* __RTL871X_SECURITY_H_ */ diff --git a/drivers/staging/rtl8723bs/include/rtw_xmit.h b/drivers/staging/rtl8723bs/include/rtw_xmit.h index 196e70865c00..c04318573f8f 100644 --- a/drivers/staging/rtl8723bs/include/rtw_xmit.h +++ b/drivers/staging/rtl8723bs/include/rtw_xmit.h @@ -183,7 +183,7 @@ struct pkt_attrib { u8 mbssid; u8 ldpc; u8 stbc; - struct sta_info * psta; + struct sta_info *psta; u8 rtsen; u8 cts2self; @@ -471,7 +471,7 @@ extern u32 rtw_calculate_wlan_pkt_size_by_attribue(struct pkt_attrib *pattrib); #define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue(&f->attrib) extern s32 rtw_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); extern s32 rtw_mgmt_xmitframe_coalesce(struct adapter *padapter, _pkt *pkt, struct xmit_frame *pxmitframe); -s32 _rtw_init_hw_txqueue(struct hw_txqueue* phw_txqueue, u8 ac_tag); +s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag); void _rtw_init_sta_xmit_priv(struct sta_xmit_priv *psta_xmitpriv); @@ -501,8 +501,8 @@ u8 qos_acm(u8 acm_mask, u8 priority); void enqueue_pending_xmitbuf(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); void enqueue_pending_xmitbuf_to_head(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf); -struct xmit_buf*dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv); -struct xmit_buf*dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv); +struct xmit_buf *dequeue_pending_xmitbuf(struct xmit_priv *pxmitpriv); +struct xmit_buf *dequeue_pending_xmitbuf_under_survey(struct xmit_priv *pxmitpriv); sint check_pending_xmitbuf(struct xmit_priv *pxmitpriv); int rtw_xmit_thread(void *context); diff --git a/drivers/staging/rtl8723bs/include/sta_info.h b/drivers/staging/rtl8723bs/include/sta_info.h index c9aa3b5097a7..734f4e2ecd66 100644 --- a/drivers/staging/rtl8723bs/include/sta_info.h +++ b/drivers/staging/rtl8723bs/include/sta_info.h @@ -378,7 +378,7 @@ extern u32 rtw_free_stainfo(struct adapter *padapter, struct sta_info *psta); extern void rtw_free_all_stainfo(struct adapter *padapter); extern struct sta_info *rtw_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr); extern u32 rtw_init_bcmc_stainfo(struct adapter *padapter); -extern struct sta_info* rtw_get_bcmc_stainfo(struct adapter *padapter); +extern struct sta_info *rtw_get_bcmc_stainfo(struct adapter *padapter); extern u8 rtw_access_ctrl(struct adapter *padapter, u8 *mac_addr); #endif /* _STA_INFO_H_ */ diff --git a/drivers/staging/rtl8723bs/include/wifi.h b/drivers/staging/rtl8723bs/include/wifi.h index 6f2d4ea51f15..b95f7f1c70de 100644 --- a/drivers/staging/rtl8723bs/include/wifi.h +++ b/drivers/staging/rtl8723bs/include/wifi.h @@ -355,20 +355,20 @@ static inline int IS_MCAST(unsigned char *da) return false; } -static inline unsigned char * get_ra(unsigned char *pframe) +static inline unsigned char *get_ra(unsigned char *pframe) { unsigned char *ra; ra = GetAddr1Ptr(pframe); return ra; } -static inline unsigned char * get_ta(unsigned char *pframe) +static inline unsigned char *get_ta(unsigned char *pframe) { unsigned char *ta; ta = GetAddr2Ptr(pframe); return ta; } -static inline unsigned char * get_da(unsigned char *pframe) +static inline unsigned char *get_da(unsigned char *pframe) { unsigned char *da; unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); @@ -392,7 +392,7 @@ static inline unsigned char * get_da(unsigned char *pframe) } -static inline unsigned char * get_sa(unsigned char *pframe) +static inline unsigned char *get_sa(unsigned char *pframe) { unsigned char *sa; unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); @@ -415,7 +415,7 @@ static inline unsigned char * get_sa(unsigned char *pframe) return sa; } -static inline unsigned char * get_hdr_bssid(unsigned char *pframe) +static inline unsigned char *get_hdr_bssid(unsigned char *pframe) { unsigned char *sa = NULL; unsigned int to_fr_ds = (GetToDs(pframe) << 1) | GetFrDs(pframe); diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c index 7676056913d8..7321f1c94311 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_cfg80211.c @@ -563,7 +563,7 @@ static int rtw_cfg80211_ap_set_encryption(struct net_device *dev, struct ieee_pa struct sta_info *psta = NULL, *pbcmc_sta = NULL; struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv* psecuritypriv = &(padapter->securitypriv); + struct security_priv *psecuritypriv = &(padapter->securitypriv); struct sta_priv *pstapriv = &padapter->stapriv; DBG_8192C("%s\n", __func__); @@ -924,8 +924,8 @@ static int rtw_cfg80211_set_encryption(struct net_device *dev, struct ieee_param if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) /* 802_1x */ { - struct sta_info * psta, *pbcmc_sta; - struct sta_priv * pstapriv = &padapter->stapriv; + struct sta_info *psta, *pbcmc_sta; + struct sta_priv *pstapriv = &padapter->stapriv; /* DBG_8192C("%s, : dot11AuthAlgrthm == dot11AuthAlgrthm_8021X\n", __func__); */ @@ -2529,8 +2529,8 @@ static const struct net_device_ops rtw_cfg80211_monitor_if_ops = { static int rtw_cfg80211_add_monitor_if(struct adapter *padapter, char *name, struct net_device **ndev) { int ret = 0; - struct net_device* mon_ndev = NULL; - struct wireless_dev* mon_wdev = NULL; + struct net_device *mon_ndev = NULL; + struct wireless_dev *mon_wdev = NULL; struct rtw_netdev_priv_indicator *pnpi; struct rtw_wdev_priv *pwdev_priv = adapter_wdev_data(padapter); @@ -2609,7 +2609,7 @@ static struct wireless_dev * enum nl80211_iftype type, struct vif_params *params) { int ret = 0; - struct net_device* ndev = NULL; + struct net_device *ndev = NULL; struct adapter *padapter = wiphy_to_adapter(wiphy); DBG_871X(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n", @@ -2911,7 +2911,7 @@ static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev, return 0; } -void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char*msg) +void rtw_cfg80211_rx_action(struct adapter *adapter, u8 *frame, uint frame_len, const char *msg) { s32 freq; int channel; diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 9c00469deeab..294c4f406fcc 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -78,7 +78,7 @@ void rtw_indicate_wx_disassoc_event(struct adapter *padapter) } static char *translate_scan(struct adapter *padapter, - struct iw_request_info* info, struct wlan_network *pnetwork, + struct iw_request_info *info, struct wlan_network *pnetwork, char *start, char *stop) { struct iw_event iwe; @@ -765,7 +765,7 @@ static int rtw_wx_get_name(struct net_device *dev, u8 ht_cap = false, vht_cap = false; struct mlme_priv *pmlmepriv = &(padapter->mlmepriv); struct wlan_bssid_ex *pcur_bss = &pmlmepriv->cur_network.network; - NDIS_802_11_RATES_EX* prates = NULL; + NDIS_802_11_RATES_EX *prates = NULL; RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("cmd_code =%x\n", info->cmd)); @@ -937,7 +937,7 @@ static int rtw_wx_set_pmkid(struct net_device *dev, u8 j, blInserted = false; int intReturn = false; struct security_priv *psecuritypriv = &padapter->securitypriv; - struct iw_pmksa* pPMK = (struct iw_pmksa *)extra; + struct iw_pmksa *pPMK = (struct iw_pmksa *)extra; u8 strZeroMacAddress[ETH_ALEN] = { 0x00 }; u8 strIssueBssid[ETH_ALEN] = { 0x00 }; @@ -3430,7 +3430,7 @@ static int rtw_set_encryption(struct net_device *dev, struct ieee_param *param, struct sta_info *psta = NULL, *pbcmc_sta = NULL; struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - struct security_priv* psecuritypriv = &(padapter->securitypriv); + struct security_priv *psecuritypriv = &(padapter->securitypriv); struct sta_priv *pstapriv = &padapter->stapriv; DBG_871X("%s\n", __func__); diff --git a/drivers/staging/rtl8723bs/os_dep/recv_linux.c b/drivers/staging/rtl8723bs/os_dep/recv_linux.c index 63c1998bec7f..ac35277fbacd 100644 --- a/drivers/staging/rtl8723bs/os_dep/recv_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/recv_linux.c @@ -33,7 +33,7 @@ void rtw_os_recv_resource_free(struct recv_priv *precvpriv) sint i; union recv_frame *precvframe; - precvframe = (union recv_frame*) precvpriv->precv_frame_buf; + precvframe = (union recv_frame *) precvpriv->precv_frame_buf; for (i = 0; i < NR_RECVFRAME; i++) { if (precvframe->u.hdr.pkt) { @@ -97,7 +97,7 @@ _pkt *rtw_os_alloc_msdu_pkt(union recv_frame *prframe, u16 nSubframe_Length, u8 void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt_attrib *pattrib) { - struct mlme_priv*pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; int ret; /* Indicate the packets to upper layer */ @@ -117,7 +117,7 @@ void rtw_os_recv_indicate_pkt(struct adapter *padapter, _pkt *pkt, struct rx_pkt } if (psta) { - struct net_device *pnetdev = (struct net_device*)padapter->pnetdev; + struct net_device *pnetdev = (struct net_device *)padapter->pnetdev; /* skb->ip_summed = CHECKSUM_NONE; */ pkt->dev = pnetdev; skb_set_queue_mapping(pkt, rtw_recv_select_queue(pkt)); @@ -165,7 +165,7 @@ void rtw_handle_tkip_mic_err(struct adapter *padapter, u8 bgroup) enum nl80211_key_type key_type = 0; union iwreq_data wrqu; struct iw_michaelmicfailure ev; - struct mlme_priv* pmlmepriv = &padapter->mlmepriv; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; struct security_priv *psecuritypriv = &padapter->securitypriv; unsigned long cur_time = 0; @@ -218,7 +218,7 @@ static void rtw_os_ksocket_send(struct adapter *padapter, union recv_frame *prec if (psta && psta->isrc && psta->pid > 0) { u16 rx_pid; - rx_pid = *(u16*)(skb->data+ETH_HLEN); + rx_pid = *(u16 *)(skb->data+ETH_HLEN); DBG_871X("eth rx(pid = 0x%x): sta(%pM) pid = 0x%x\n", rx_pid, MAC_ARG(psta->hwaddr), psta->pid); -- 2.25.1 From ross.schm.dev at gmail.com Tue Nov 10 04:10:08 2020 From: ross.schm.dev at gmail.com (Ross Schmidt) Date: Mon, 9 Nov 2020 22:10:08 -0600 Subject: [PATCH 10/10] staging: rtl8723bs: clean up leading space In-Reply-To: <20201110041008.15847-1-ross.schm.dev@gmail.com> References: <20201110041008.15847-1-ross.schm.dev@gmail.com> Message-ID: <20201110041008.15847-10-ross.schm.dev@gmail.com> Convert spaces to tabs to fix coding style issues and clear checkpatch warnings. WARNING: please, no spaces at the start of a line Signed-off-by: Ross Schmidt --- .../staging/rtl8723bs/os_dep/ioctl_linux.c | 80 +++++++++---------- .../staging/rtl8723bs/os_dep/osdep_service.c | 2 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c index 294c4f406fcc..6c38eb239381 100644 --- a/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8723bs/os_dep/ioctl_linux.c @@ -985,23 +985,23 @@ static int rtw_wx_set_pmkid(struct net_device *dev, if (psecuritypriv->PMKIDIndex == 16) psecuritypriv->PMKIDIndex = 0; } - } else if (pPMK->cmd == IW_PMKSA_REMOVE) { - DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); - intReturn = true; + } else if (pPMK->cmd == IW_PMKSA_REMOVE) { + DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_REMOVE!\n"); + intReturn = true; for (j = 0; j < NUM_PMKID_CACHE; j++) { if (!memcmp(psecuritypriv->PMKIDList[j].Bssid, strIssueBssid, ETH_ALEN)) { /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */ - eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid); - psecuritypriv->PMKIDList[j].bUsed = false; + eth_zero_addr(psecuritypriv->PMKIDList[j].Bssid); + psecuritypriv->PMKIDList[j].bUsed = false; break; } } - } else if (pPMK->cmd == IW_PMKSA_FLUSH) { - DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); - memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); - psecuritypriv->PMKIDIndex = 0; - intReturn = true; - } + } else if (pPMK->cmd == IW_PMKSA_FLUSH) { + DBG_871X("[rtw_wx_set_pmkid] IW_PMKSA_FLUSH!\n"); + memset(&psecuritypriv->PMKIDList[0], 0x00, sizeof(RT_PMKID_LIST) * NUM_PMKID_CACHE); + psecuritypriv->PMKIDIndex = 0; + intReturn = true; + } return intReturn; } @@ -2222,8 +2222,8 @@ static int rtw_wx_get_nick(struct net_device *dev, } static int rtw_wx_read32(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter; struct iw_point *p; @@ -2282,8 +2282,8 @@ static int rtw_wx_read32(struct net_device *dev, } static int rtw_wx_write32(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter = rtw_netdev_priv(dev); @@ -2319,8 +2319,8 @@ static int rtw_wx_write32(struct net_device *dev, } static int rtw_wx_read_rf(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter = rtw_netdev_priv(dev); u32 path, addr, data32; @@ -2340,8 +2340,8 @@ static int rtw_wx_read_rf(struct net_device *dev, } static int rtw_wx_write_rf(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter = rtw_netdev_priv(dev); u32 path, addr, data32; @@ -2375,8 +2375,8 @@ static int dummy(struct net_device *dev, struct iw_request_info *a, } static int rtw_wx_set_channel_plan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { struct adapter *padapter = rtw_netdev_priv(dev); u8 channel_plan_req = (u8)(*((int *)wrqu)); @@ -2425,8 +2425,8 @@ static int rtw_drvext_hdl(struct net_device *dev, struct iw_request_info *info, } static int rtw_get_ap_info(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; int wpa_ielen; @@ -2523,8 +2523,8 @@ static int rtw_get_ap_info(struct net_device *dev, } static int rtw_set_pid(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; @@ -2552,8 +2552,8 @@ static int rtw_set_pid(struct net_device *dev, } static int rtw_wps_start(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; @@ -2582,8 +2582,8 @@ static int rtw_wps_start(struct net_device *dev, } static int rtw_p2p_set(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { return 0; @@ -2591,8 +2591,8 @@ static int rtw_p2p_set(struct net_device *dev, } static int rtw_p2p_get(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { return 0; @@ -2609,8 +2609,8 @@ static int rtw_p2p_get2(struct net_device *dev, } static int rtw_rereg_nd_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; struct adapter *padapter = rtw_netdev_priv(dev); @@ -2658,8 +2658,8 @@ static int rtw_rereg_nd_name(struct net_device *dev, } static int rtw_dbg_port(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { u8 major_cmd, minor_cmd; u16 arg; @@ -3014,7 +3014,7 @@ static int rtw_dbg_port(struct net_device *dev, pregistrypriv->ldpc_cap = (u8)(extra_arg&0x33); } } - break; + break; case 0x1a: { struct registry_priv *pregistrypriv = &padapter->registrypriv; @@ -3029,7 +3029,7 @@ static int rtw_dbg_port(struct net_device *dev, pregistrypriv->stbc_cap = (u8)(extra_arg&0x33); } } - break; + break; case 0x1b: { struct registry_priv *pregistrypriv = &padapter->registrypriv; @@ -3065,7 +3065,7 @@ static int rtw_dbg_port(struct net_device *dev, } } } - break; + break; case 0x1c: /* enable/disable driver control AMPDU Density for peer sta's rx */ { if (arg == 0) { @@ -4409,8 +4409,8 @@ static int rtw_wx_set_priv(struct net_device *dev, } static int rtw_pm_set(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) { int ret = 0; unsigned mode = 0; diff --git a/drivers/staging/rtl8723bs/os_dep/osdep_service.c b/drivers/staging/rtl8723bs/os_dep/osdep_service.c index f61ad9200960..3c71d2fafabf 100644 --- a/drivers/staging/rtl8723bs/os_dep/osdep_service.c +++ b/drivers/staging/rtl8723bs/os_dep/osdep_service.c @@ -272,7 +272,7 @@ void *rtw_cbuf_pop(struct rtw_cbuf *cbuf) if (rtw_cbuf_empty(cbuf)) return NULL; - DBG_871X("%s on %u\n", __func__, cbuf->read); + DBG_871X("%s on %u\n", __func__, cbuf->read); buf = cbuf->bufs[cbuf->read]; cbuf->read = (cbuf->read + 1) % cbuf->size; -- 2.25.1 From ira.weiny at intel.com Tue Nov 10 04:59:54 2020 From: ira.weiny at intel.com (Ira Weiny) Date: Mon, 9 Nov 2020 20:59:54 -0800 Subject: [PATCH RFC PKS/PMEM 05/58] kmap: Introduce k[un]map_thread In-Reply-To: <87h7pyhv3f.fsf@nanos.tec.linutronix.de> References: <20201009195033.3208459-1-ira.weiny@intel.com> <20201009195033.3208459-6-ira.weiny@intel.com> <87h7pyhv3f.fsf@nanos.tec.linutronix.de> Message-ID: <20201110045954.GL3976735@iweiny-DESK2.sc.intel.com> On Tue, Nov 10, 2020 at 02:13:56AM +0100, Thomas Gleixner wrote: > Ira, > > On Fri, Oct 09 2020 at 12:49, ira weiny wrote: > > From: Ira Weiny > > > > To correctly support the semantics of kmap() with Kernel protection keys > > (PKS), kmap() may be required to set the protections on multiple > > processors (globally). Enabling PKS globally can be very expensive > > depending on the requested operation. Furthermore, enabling a domain > > globally reduces the protection afforded by PKS. > > > > Most kmap() (Aprox 209 of 229) callers use the map within a single thread and > > have no need for the protection domain to be enabled globally. However, the > > remaining callers do not follow this pattern and, as best I can tell, expect > > the mapping to be 'global' and available to any thread who may access the > > mapping.[1] > > > > We don't anticipate global mappings to pmem, however in general there is a > > danger in changing the semantics of kmap(). Effectively, this would cause an > > unresolved page fault with little to no information about why the failure > > occurred. > > > > To resolve this a number of options were considered. > > > > 1) Attempt to change all the thread local kmap() calls to kmap_atomic()[2] > > 2) Introduce a flags parameter to kmap() to indicate if the mapping should be > > global or not > > 3) Change ~20 call sites to 'kmap_global()' to indicate that they require a > > global enablement of the pages. > > 4) Change ~209 call sites to 'kmap_thread()' to indicate that the mapping is to > > be used within that thread of execution only > > > > Option 1 is simply not feasible. Option 2 would require all of the call sites > > of kmap() to change. Option 3 seems like a good minimal change but there is a > > danger that new code may miss the semantic change of kmap() and not get the > > behavior the developer intended. Therefore, #4 was chosen. > > There is Option #5: There is now yes. :-D > > Convert the thread local kmap() invocations to the proposed kmap_local() > interface which is coming along [1]. I've been trying to follow that thread. > > That solves a couple of issues: > > 1) It relieves the current kmap_atomic() usage sites from the implict > pagefault/preempt disable semantics which apply even when > CONFIG_HIGHMEM is disabled. kmap_local() still can be invoked from > atomic context. > > 2) Due to #1 it allows to replace the conditional usage of kmap() and > kmap_atomic() for purely thread local mappings. > > 3) It puts the burden on the HIGHMEM inflicted systems > > 4) It is actually more efficient for most of the pure thread local use > cases on HIGHMEM inflicted systems because it avoids the overhead of > the global lock and the potential kmap slot exhaustion. A potential > preemption will be more expensive, but that's not really the case we > want to optimize for. > > 5) It solves the RT issue vs. kmap_atomic() > > So instead of creating yet another variety of kmap() which is just > scratching the particular PKRS itch, can we please consolidate all of > that on the wider reaching kmap_local() approach? Yes I agree. We absolutely don't want more kmap*() calls and I was hoping to dovetail into your kmap_local() work.[2] I've pivoted away from this work a bit to clean up all the kmap()/memcpy*()/kunmaps() as discussed elsewhere in the thread first.[3] I was hoping your work would land and then I could s/kmap_thread()/kmap_local()/ on all of these patches. Also, we can convert the new memcpy_*_page() calls to kmap_local() as well. [For now my patch just uses kmap_atomic().] I've not looked at all of the patches in your latest version. Have you included converting any of the kmap() call sites? I thought you were more focused on converting the kmap_atomic() to kmap_local()? Ira > > Thanks, > > tglx > > [1] https://lore.kernel.org/lkml/20201103092712.714480842 at linutronix.de/ [2] https://lore.kernel.org/lkml/20201012195354.GC2046448 at iweiny-DESK2.sc.intel.com/ [3] https://lore.kernel.org/lkml/20201009213434.GA839 at sol.localdomain/ https://lore.kernel.org/lkml/20201013200149.GI3576660 at ZenIV.linux.org.uk/ From lkp at intel.com Tue Nov 10 06:08:29 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 10 Nov 2020 14:08:29 +0800 Subject: [driver-core:driver-core-testing] BUILD SUCCESS 33c0c9bdf7a59051a654cd98b7d2b48ce0080967 Message-ID: <5faa2e5d.bTNrp1FspeNbIx+J%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git driver-core-testing branch HEAD: 33c0c9bdf7a59051a654cd98b7d2b48ce0080967 drivers: base: fix some kernel-doc markups elapsed time: 724m configs tested: 152 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig mips decstation_defconfig arm spear6xx_defconfig sh r7785rp_defconfig sh shx3_defconfig arm ixp4xx_defconfig powerpc mpc5200_defconfig sh rts7751r2d1_defconfig mips malta_kvm_defconfig sh ecovec24-romimage_defconfig parisc generic-64bit_defconfig x86_64 defconfig sh urquell_defconfig powerpc gamecube_defconfig mips maltaaprp_defconfig xtensa nommu_kc705_defconfig powerpc mgcoge_defconfig powerpc mpc832x_mds_defconfig x86_64 alldefconfig mips qi_lb60_defconfig m68k m5275evb_defconfig h8300 defconfig powerpc tqm8541_defconfig powerpc tqm8xx_defconfig sh espt_defconfig arc nsim_700_defconfig i386 defconfig powerpc mpc8315_rdb_defconfig powerpc maple_defconfig sh alldefconfig m68k amcore_defconfig powerpc katmai_defconfig sh sh7770_generic_defconfig powerpc motionpro_defconfig powerpc tqm5200_defconfig arm mvebu_v7_defconfig powerpc mpc85xx_cds_defconfig arm tct_hammer_defconfig arm keystone_defconfig arm ezx_defconfig mips sb1250_swarm_defconfig arm omap2plus_defconfig riscv alldefconfig arm realview_defconfig xtensa audio_kc705_defconfig xtensa defconfig powerpc ep8248e_defconfig powerpc asp8347_defconfig mips nlm_xlr_defconfig arm multi_v5_defconfig powerpc stx_gp3_defconfig mips jazz_defconfig arm mmp2_defconfig arm cerfcube_defconfig m68k m5272c3_defconfig arm oxnas_v6_defconfig sh rsk7203_defconfig arm cns3420vb_defconfig arm omap1_defconfig c6x evmc6472_defconfig powerpc sequoia_defconfig powerpc tqm8548_defconfig sh hp6xx_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig arc defconfig xtensa allyesconfig h8300 allyesconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig x86_64 randconfig-a003-20201110 x86_64 randconfig-a005-20201110 x86_64 randconfig-a004-20201110 x86_64 randconfig-a002-20201110 x86_64 randconfig-a006-20201110 x86_64 randconfig-a001-20201110 i386 randconfig-a006-20201110 i386 randconfig-a005-20201110 i386 randconfig-a002-20201110 i386 randconfig-a001-20201110 i386 randconfig-a003-20201110 i386 randconfig-a004-20201110 i386 randconfig-a004-20201109 i386 randconfig-a006-20201109 i386 randconfig-a005-20201109 i386 randconfig-a001-20201109 i386 randconfig-a003-20201109 i386 randconfig-a002-20201109 i386 randconfig-a012-20201110 i386 randconfig-a014-20201110 i386 randconfig-a016-20201110 i386 randconfig-a011-20201110 i386 randconfig-a015-20201110 i386 randconfig-a013-20201110 i386 randconfig-a014-20201109 i386 randconfig-a015-20201109 i386 randconfig-a013-20201109 i386 randconfig-a016-20201109 i386 randconfig-a011-20201109 i386 randconfig-a012-20201109 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a015-20201110 x86_64 randconfig-a011-20201110 x86_64 randconfig-a014-20201110 x86_64 randconfig-a013-20201110 x86_64 randconfig-a016-20201110 x86_64 randconfig-a012-20201110 x86_64 randconfig-a012-20201109 x86_64 randconfig-a015-20201109 x86_64 randconfig-a013-20201109 x86_64 randconfig-a011-20201109 x86_64 randconfig-a014-20201109 x86_64 randconfig-a016-20201109 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From tglx at linutronix.de Tue Nov 10 08:48:31 2020 From: tglx at linutronix.de (Thomas Gleixner) Date: Tue, 10 Nov 2020 09:48:31 +0100 Subject: [PATCH RFC PKS/PMEM 05/58] kmap: Introduce k[un]map_thread In-Reply-To: <20201110045954.GL3976735@iweiny-DESK2.sc.intel.com> References: <20201009195033.3208459-1-ira.weiny@intel.com> <20201009195033.3208459-6-ira.weiny@intel.com> <87h7pyhv3f.fsf@nanos.tec.linutronix.de> <20201110045954.GL3976735@iweiny-DESK2.sc.intel.com> Message-ID: <87eel1iom8.fsf@nanos.tec.linutronix.de> On Mon, Nov 09 2020 at 20:59, Ira Weiny wrote: > On Tue, Nov 10, 2020 at 02:13:56AM +0100, Thomas Gleixner wrote: > Also, we can convert the new memcpy_*_page() calls to kmap_local() as well. > [For now my patch just uses kmap_atomic().] > > I've not looked at all of the patches in your latest version. Have you > included converting any of the kmap() call sites? I thought you were more > focused on converting the kmap_atomic() to kmap_local()? I did not touch any of those yet, but it's a logical consequence to convert all kmap() instances which are _not_ creating a global mapping over to it. Thanks, tglx From dan.carpenter at oracle.com Tue Nov 10 08:48:26 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Tue, 10 Nov 2020 11:48:26 +0300 Subject: [PATCH v2] drivers: most: add ALSA sound driver In-Reply-To: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> References: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> Message-ID: <20201110084826.GE29398@kadam> On Fri, Nov 06, 2020 at 05:30:54PM +0100, Christian Gromm wrote: > +static struct list_head adpt_list; > + > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > + SNDRV_PCM_INFO_MMAP_VALID | \ > + SNDRV_PCM_INFO_BATCH | \ > + SNDRV_PCM_INFO_INTERLEAVED | \ > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > + > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < (bytes / 2)) { > + dest[i] = swab16(source[i]); > + i++; > + } > +} > + > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < bytes - 2) { Can bytes ever be zero? If so then this will corrupt memory and crash. Generally "int i;" is less risky than "unsigned int i;". Of course, I recently almost introduced a situation where we were copying up to ULONG_MAX bytes so there are times when iterators should be size_t so that does happen. It could be buggy either way is what I'm saying but generally "unsigned int i;" is more often buggy. > + dest[i] = source[i + 2]; > + dest[i + 1] = source[i + 1]; > + dest[i + 2] = source[i]; > + i += 3; > + } > +} > + > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) > +{ > + unsigned int i = 0; > + > + while (i < bytes / 4) { > + dest[i] = swab32(source[i]); > + i++; > + } > +} > + > +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) > +{ > + memcpy(most, alsa, bytes); > +} > + > +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy16(most, alsa, bytes); > +} > + > +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy24(most, alsa, bytes); > +} > + > +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy32(most, alsa, bytes); > +} > + > +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) > +{ > + memcpy(alsa, most, bytes); > +} > + > +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy16(alsa, most, bytes); > +} > + > +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy24(alsa, most, bytes); > +} > + > +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) > +{ > + swap_copy32(alsa, most, bytes); > +} > + > +/** > + * get_channel - get pointer to channel > + * @iface: interface structure > + * @channel_id: channel ID > + * > + * This traverses the channel list and returns the channel matching the > + * ID and interface. > + * > + * Returns pointer to channel on success or NULL otherwise. > + */ > +static struct channel *get_channel(struct most_interface *iface, > + int channel_id) > +{ > + struct sound_adapter *adpt = iface->priv; > + struct channel *channel, *tmp; > + > + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { > + if ((channel->iface == iface) && (channel->id == channel_id)) > + return channel; No need to use the _safe() version of this loop macro. You're not freeing anything. My concern is that sometimes people think the _safe() has something to do with locking and it does not. > + } > + return NULL; > +} > + [ Snip ] > +/** > + * audio_probe_channel - probe function of the driver module > + * @iface: pointer to interface instance > + * @channel_id: channel index/ID > + * @cfg: pointer to actual channel configuration > + * @arg_list: string that provides the name of the device to be created in /dev > + * plus the desired audio resolution > + * > + * Creates sound card, pcm device, sets pcm ops and registers sound card. > + * > + * Returns 0 on success or error code otherwise. > + */ > +static int audio_probe_channel(struct most_interface *iface, int channel_id, > + struct most_channel_config *cfg, > + char *device_name, char *arg_list) > +{ > + struct channel *channel; > + struct sound_adapter *adpt; > + struct snd_pcm *pcm; > + int playback_count = 0; > + int capture_count = 0; > + int ret; > + int direction; > + u16 ch_num; > + char *sample_res; > + char arg_list_cpy[STRING_SIZE]; > + > + if (cfg->data_type != MOST_CH_SYNC) { > + pr_err("Incompatible channel type\n"); > + return -EINVAL; > + } > + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); > + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); > + if (ret < 0) > + return ret; > + > + list_for_each_entry(adpt, &adpt_list, list) { > + if (adpt->iface != iface) > + continue; > + if (adpt->registered) > + return -ENOSPC; > + adpt->pcm_dev_idx++; > + goto skip_adpt_alloc; It's weird how if the "channel = " allocation fails, then we free this "adpt" which we didn't allocate. > + } > + adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); > + if (!adpt) > + return -ENOMEM; > + > + adpt->iface = iface; > + INIT_LIST_HEAD(&adpt->dev_list); > + iface->priv = adpt; > + list_add_tail(&adpt->list, &adpt_list); > + ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, > + sizeof(*channel), &adpt->card); > + if (ret < 0) > + goto err_free_adpt; > + snprintf(adpt->card->driver, sizeof(adpt->card->driver), > + "%s", DRIVER_NAME); > + snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), > + "Microchip INIC"); > + snprintf(adpt->card->longname, sizeof(adpt->card->longname), > + "%s at %s", adpt->card->shortname, iface->description); > +skip_adpt_alloc: > + if (get_channel(iface, channel_id)) { > + pr_err("channel (%s:%d) is already linked\n", > + iface->description, channel_id); > + return -EEXIST; > + } > + > + if (cfg->direction == MOST_CH_TX) { > + playback_count = 1; > + direction = SNDRV_PCM_STREAM_PLAYBACK; > + } else { > + capture_count = 1; > + direction = SNDRV_PCM_STREAM_CAPTURE; > + } > + channel = kzalloc(sizeof(*channel), GFP_KERNEL); > + if (!channel) { > + ret = -ENOMEM; > + goto err_free_adpt; > + } > + channel->card = adpt->card; > + channel->cfg = cfg; > + channel->iface = iface; > + channel->id = channel_id; > + init_waitqueue_head(&channel->playback_waitq); > + list_add_tail(&channel->list, &adpt->dev_list); > + > + ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, > + cfg); > + if (ret) > + goto err_free_adpt; > + > + ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, > + playback_count, capture_count, &pcm); I don't see any snd_pcm_free() to match this snd_pcm_new(). > + > + if (ret < 0) > + goto err_free_adpt; > + > + pcm->private_data = channel; > + strscpy(pcm->name, device_name, sizeof(pcm->name)); > + snd_pcm_set_ops(pcm, direction, &pcm_ops); > + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); > + return 0; > + > +err_free_adpt: > + release_adapter(adpt); > + return ret; > +} regards, dan carpenter From sergio.paracuellos at gmail.com Tue Nov 10 12:14:49 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Tue, 10 Nov 2020 13:14:49 +0100 Subject: [PATCH v4 0/4] MT7621 PCIe PHY In-Reply-To: <20201031122246.16497-1-sergio.paracuellos@gmail.com> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> Message-ID: Hi, On Sat, Oct 31, 2020 at 1:22 PM Sergio Paracuellos wrote: > > This series adds support for the PCIe PHY found in the Mediatek > MT7621 SoC. > > This is the first attempt to get feedback of what is missing in > this driver to be promoted from staging. > > There is also a 'mt7621-pci' driver which is the controller part > which is still in staging and is a client of this phy. > > Both drivers have been tested together in a gnubee1 board. > > This series are rebased on the top of linux-next: > commit 4e78c578cb98 ("Add linux-next specific files for 20201030") > > Changes in v4: > - Bindings moved from txt to yaml so previous Rob's Reviewed-by > is not in the new patch with the yaml file. > - 'phy-cells' property means now if phy is dual-ported. > - Avoid custom 'xlate' function and properly set registers > when the phy is dual ported. > - Add use of 'builtin_platform_driver'. > - Added a patch including myself as maintainer in the > MAINTAINERS file. > - Add a patch removing patch from staging to make easier > the complete inclusion and avoid possible problems might > appear in 'linux-next' if the series are included. Kishon, Vinod, any comments on this? Is here something wrong or missing in order to get this accepted through your tree? Thanks in advance for your time. Best regards, Sergio Paracuellos > > Changes in v3: > - Recollect Rob's Reviewed-by of bindings. > - Make Kishon Vijay suggested changes in v2: > (See https://lkml.org/lkml/2019/4/17/53) > - Kconfig: > * Add depends on COMPILE_TEST > * Select REGMAP_MMIO > - Make use of 'soc_device_attribute' and 'soc_device_match' > - Use regmap mmio API instead of directly 'readl' and 'writel'. > - Use 'platform_get_resource' instead of 'of_address_to_resource'. > > Changes in v2: > - Reorder patches to get bindings first in the series. > - Don't use child nodes in the device tree. Use #phy-cells=1 instead. > - Update driver code with new 'xlate' function for the new device tree. > - Minor changes in driver's macros changing some spaces to tabs. > > Thanks in advance for your time. > > Best regards, > Sergio Paracuellos > > Sergio Paracuellos (4): > dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY > phy: ralink: Add PHY driver for MT7621 PCIe PHY > MAINTAINERS: add MT7621 PHY PCI maintainer > staging: mt7621-pci-phy: remove driver from staging > > .../devicetree/bindings/phy}/mediatek,mt7621-pci-phy.yaml | 0 > MAINTAINERS | 6 ++++++ > drivers/phy/ralink/Kconfig | 8 ++++++++ > drivers/phy/ralink/Makefile | 1 + > .../pci-mt7621-phy.c => phy/ralink/phy-mt7621-pci.c} | 0 > drivers/staging/Kconfig | 2 -- > drivers/staging/Makefile | 1 - > drivers/staging/mt7621-pci-phy/Kconfig | 8 -------- > drivers/staging/mt7621-pci-phy/Makefile | 2 -- > drivers/staging/mt7621-pci-phy/TODO | 4 ---- > 10 files changed, 15 insertions(+), 17 deletions(-) > rename {drivers/staging/mt7621-pci-phy => Documentation/devicetree/bindings/phy}/mediatek,mt7621-pci-phy.yaml (100%) > rename drivers/{staging/mt7621-pci-phy/pci-mt7621-phy.c => phy/ralink/phy-mt7621-pci.c} (100%) > delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig > delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile > delete mode 100644 drivers/staging/mt7621-pci-phy/TODO > > -- > 2.25.1 > From nsaenzjulienne at suse.de Tue Nov 10 13:38:52 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Tue, 10 Nov 2020 14:38:52 +0100 Subject: [PATCH v3 01/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-2-nsaenzjulienne@suse.de> <47eaba0bc71c6e23bff87b8a01cebf0c6d12efd0.camel@suse.de> Message-ID: <25933d5863cd6ddb98dea25bdedf342ebd063480.camel@suse.de> Hi Bartosz, thanks for the feedback. On Thu, 2020-11-05 at 10:42 +0100, Bartosz Golaszewski wrote: > On Thu, Nov 5, 2020 at 10:28 AM Nicolas Saenz Julienne > wrote: > > Hi Bartosz, thanks for the review. > > > > On Thu, 2020-11-05 at 10:13 +0100, Bartosz Golaszewski wrote: > > > > +/** > > > > + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. > > > > + * @firmware_node: Pointer to the firmware Device Tree node. > > > > + * > > > > + * Returns NULL is the firmware device is not ready. > > > > + */ > > > > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > > > > + struct device_node *firmware_node) > > > > +{ > > > > + struct platform_device *pdev = of_find_device_by_node(firmware_node); > > > > + struct rpi_firmware *fw; > > > > + > > > > + if (!pdev) > > > > + return NULL; > > > > + > > > > + fw = platform_get_drvdata(pdev); > > > > + if (!fw) > > > > + return NULL; > > > > + > > > > + if (!refcount_inc_not_zero(&fw->consumers)) > > > > + return NULL; > > > > + > > > > + if (devm_add_action_or_reset(dev, rpi_firmware_put, fw)) > > > > + return NULL; > > > > + > > > > + return fw; > > > > +} > > > > +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); > > > > > > Usually I'd expect the devres variant to simply call > > > rpi_firmware_get() and then schedule a release callback which would > > > call whatever function is the release counterpart for it currently. > > > Devres actions are for drivers which want to schedule some more > > > unusual tasks at driver detach. Any reason for designing it this way? > > > > Yes, see patch #8 where I get rid of rpi_firmware_get() altogether after > > converting all users to devres. Since there is no use for the vanilla version > > of the function anymore, I figured it'd be better to merge everything into > > devm_rpi_firmware_get(). That said it's not something I have strong feelings > > about. > > > > I see. So the previous version didn't really have any reference > counting and it leaked the reference returned by > of_find_device_by_node(), got it. Could you just clarify for me the > logic behind the wait_queue in rpi_firmware_remove()? If the firmware > driver gets detached and remove() stops on the wait_queue - it will be > stuck until the last user releases the firmware. I'm not sure this is > correct. Yes, that's what I meant to implement. > I'd prefer to see a kref with a release callback and remove > would simply decrease the kref and return. Each user would do the same > and then after the last user is detached the firmware would be > destroyed. Sounds good to me. I'll update it. > Don't we really have some centralized firmware subsystem that would handle this? Sadly no, this is an RPi specific thing, it doesn't live behind a standard like other firmware based protocols (for ex. SCMI), and evolves as the needs arise. Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From dan.carpenter at oracle.com Tue Nov 10 18:49:03 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Tue, 10 Nov 2020 21:49:03 +0300 Subject: [PATCH v3 00/11] Introduce Simple atomic counters In-Reply-To: <202010161541.6DD2D1E@keescook> References: <20201009193746.GA1073957@hirez.programming.kicks-ass.net> <202010091255.246395A6@keescook> <20201010110920.GQ2628@hirez.programming.kicks-ass.net> <6e1dd408-653e-817e-b659-23649259a929@linuxfoundation.org> <20201014091720.GC2628@hirez.programming.kicks-ass.net> <202010141611.70B7A38@keescook> <20201016105313.GJ2611@hirez.programming.kicks-ass.net> <202010161541.6DD2D1E@keescook> Message-ID: <20201110184903.GG29398@kadam> On Fri, Oct 16, 2020 at 03:51:25PM -0700, Kees Cook wrote: > On Fri, Oct 16, 2020 at 12:53:13PM +0200, Peter Zijlstra wrote: > > That's like saying: "I'm too lazy to track what I've looked at already". > > You're basically proposing to graffiti "Kees was here -- 16/10/2020" all > > over the kernel. Just so you can see where you still need to go. > > > > It says the code was (assuming your audit was correct) good at that > > date, but has no guarantees for any moment after that. > > That kind of bit-rot marking is exactly what I would like to avoid: just > putting a comment in is pointless. Making the expectations of the usage > become _enforced_ is the goal. And having it enforced by the _compiler_ > is key. Just adding a meaningless attribute that a static checker > will notice some time and hope people fix them doesn't scale either > (just look at how many sparse warnings there are). Most Sparse warnings are false positives. People do actually fix the ones which matter. I think this patchset could be useful. I'm working on a refcounting check for Smatch. I want to warn about when we forget to drop a reference on an error path. Right now I just assume that anything with "error", "drop" or "->stats->" in the name is just a counter. regards, dan carpenter From skhan at linuxfoundation.org Tue Nov 10 19:53:35 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Tue, 10 Nov 2020 12:53:35 -0700 Subject: [PATCH 09/13] drivers/staging/rtl8723bs: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <500cc03f4fdea0237576913cfc739ae26d8a0b58.1605027593.git.skhan@linuxfoundation.org> seqnum_ops api is introduced to be used when a variable is used as a sequence/stat counter and doesn't guard object lifetimes. This clearly differentiates atomic_t usages that guard object lifetimes. seqnum32 variables wrap around to INT_MIN when it overflows and should not be used to guard resource lifetimes, device usage and open counts that control state changes, and pm states. atomic_t variables used for stats are atomic counters. Overflow will wrap around and reset the stats and no change with the conversion. Convert them to use seqnum_ops. This conversion replaces inc_return() with _inc() followed by _read(). Signed-off-by: Shuah Khan --- drivers/staging/rtl8723bs/core/rtw_cmd.c | 3 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 33 +++++++++++++------ drivers/staging/rtl8723bs/include/rtw_cmd.h | 3 +- .../staging/rtl8723bs/include/rtw_mlme_ext.h | 3 +- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 2abe205e3453..c3350f97816d 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -10,6 +10,7 @@ #include #include #include +#include static struct _cmd_callback rtw_cmd_callback[] = { {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ @@ -207,7 +208,7 @@ static void c2h_wk_callback(_workitem * work); int rtw_init_evt_priv(struct evt_priv *pevtpriv) { /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - atomic_set(&pevtpriv->event_seq, 0); + seqnum32_set(&pevtpriv->event_seq, 0); pevtpriv->evt_done_cnt = 0; _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index b912ad2f4b72..addcd11b153b 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -11,6 +11,7 @@ #include #include #include +#include #include static struct mlme_handler mlme_sta_tbl[] = { @@ -281,7 +282,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - atomic_set(&pmlmeext->event_seq, 0); + seqnum32_set(&pmlmeext->event_seq, 0); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ pmlmeext->sa_query_seq = 0; pmlmeext->mgnt_80211w_IPN = 0; @@ -5051,7 +5052,9 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); @@ -5104,7 +5107,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -5151,7 +5156,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); @@ -5202,7 +5209,9 @@ void report_wmm_edca_update(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct wmm_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); pwmm_event->wmm = 0; @@ -5249,7 +5258,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -5302,7 +5313,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -6620,10 +6633,10 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) #ifdef CHECK_EVENT_SEQ /* checking event sequence... */ - if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) { + if (evt_seq != (seqnum32_read(&pevt_priv->event_seq) & 0x7f)) { RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("Event Seq Error! %d vs %d\n", (evt_seq & 0x7f), - (atomic_read(&pevt_priv->event_seq) & 0x7f))); + (seqnum32_read(&pevt_priv->event_seq) & 0x7f))); pevt_priv->event_seq = (evt_seq+1)&0x7f; @@ -6647,7 +6660,7 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) } - atomic_inc(&pevt_priv->event_seq); + seqnum32_inc(&pevt_priv->event_seq); peventbuf += 2; diff --git a/drivers/staging/rtl8723bs/include/rtw_cmd.h b/drivers/staging/rtl8723bs/include/rtw_cmd.h index 56c77bc7ca81..cc0ea649388b 100644 --- a/drivers/staging/rtl8723bs/include/rtw_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtw_cmd.h @@ -8,6 +8,7 @@ #define __RTW_CMD_H_ #include +#include #define C2H_MEM_SZ (16*1024) @@ -62,7 +63,7 @@ struct rtw_cbuf *c2h_queue; #define C2H_QUEUE_MAX_LEN 10 - atomic_t event_seq; + struct seqnum32 event_seq; u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ u8 *evt_allocated_buf; u32 evt_done_cnt; diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 1567831caf91..ebb050253bcf 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_ +#include /* Commented by Albert 20101105 */ /* Increase the SURVEY_TO value from 100 to 150 (100ms to 150ms) */ @@ -461,7 +462,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq; u16 sa_query_seq; u64 mgnt_80211w_IPN; -- 2.27.0 From skhan at linuxfoundation.org Tue Nov 10 19:53:37 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Tue, 10 Nov 2020 12:53:37 -0700 Subject: [PATCH 11/13] drivers/staging/rtl8188eu: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <07ada10228dbd8d8954a30d6604fef2db762be69.1605027593.git.skhan@linuxfoundation.org> seqnum_ops api is introduced to be used when a variable is used as a sequence/stat counter and doesn't guard object lifetimes. This clearly differentiates atomic_t usages that guard object lifetimes. seqnum32 variables wrap around to INT_MIN when it overflows and should not be used to guard resource lifetimes, device usage and open counts that control state changes, and pm states. atomic_t variables used for stats are atomic counters. Overflow will wrap around and reset the stats and no change with the conversion. Convert them to use seqnum_ops. This conversion replaces inc_return() with _inc() followed by _read(). Signed-off-by: Shuah Khan --- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 23 ++++++++++++++----- .../staging/rtl8188eu/include/rtw_mlme_ext.h | 3 ++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index b3eddcb83cd0..31dd9d31dd9a 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -7,6 +7,7 @@ #define _RTW_MLME_EXT_C_ #include +#include #include #include @@ -3860,7 +3861,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) _12M_RATE_, _24M_RATE_, 0xff, }; - atomic_set(&pmlmeext->event_seq, 0); + seqnum32_set(&pmlmeext->event_seq, 0); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ pmlmeext->cur_channel = padapter->registrypriv.channel; @@ -4189,7 +4190,9 @@ void report_survey_event(struct adapter *padapter, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = _Survey_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); @@ -4239,7 +4242,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = _SurveyDone_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -4283,7 +4288,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = _JoinBss_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&pjoinbss_evt->network.network), &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); @@ -4333,7 +4340,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = _DelSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&pdel_sta_evt->macaddr), MacAddr); @@ -4386,7 +4395,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = _AddSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + seqnum32_inc(&pmlmeext->event_seq); + pc2h_evt_hdr->seq = seqnum32_read(&pmlmeext->event_seq); padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&padd_sta_evt->macaddr), MacAddr); diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h index b11a6886a083..09b7e3bb2738 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_ +#include #include #include #include @@ -393,7 +394,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq; unsigned char cur_channel; -- 2.27.0 From skhan at linuxfoundation.org Tue Nov 10 19:53:38 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Tue, 10 Nov 2020 12:53:38 -0700 Subject: [PATCH 12/13] drivers/staging/unisys/visorhba: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <6fb679d23de785bbd1be6a528127e29f8ee6abd7.1605027593.git.skhan@linuxfoundation.org> seqnum_ops api is introduced to be used when a variable is used as a sequence/stat counter and doesn't guard object lifetimes. This clearly differentiates atomic_t usages that guard object lifetimes. seqnum32 variables wrap around to INT_MIN when it overflows and should not be used to guard resource lifetimes, device usage and open counts that control state changes, and pm states. atomic_t variables used for error_count and ios_threshold are atomic counters and guarded by max. values. No change to the behavior with this change. Signed-off-by: Shuah Khan --- .../staging/unisys/visorhba/visorhba_main.c | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 7ae5306b92fe..3209958b8aaa 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -41,8 +42,8 @@ MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR); struct visordisk_info { struct scsi_device *sdev; u32 valid; - atomic_t ios_threshold; - atomic_t error_count; + struct seqnum32 ios_threshold; + struct seqnum32 error_count; struct visordisk_info *next; }; @@ -374,10 +375,10 @@ static int visorhba_abort_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc(&vdisk->error_count); else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + seqnum32_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); rtn = forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsidev); if (rtn == SUCCESS) { scsicmd->result = DID_ABORT << 16; @@ -401,10 +402,10 @@ static int visorhba_device_reset_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc(&vdisk->error_count); else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + seqnum32_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); rtn = forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsidev); if (rtn == SUCCESS) { scsicmd->result = DID_RESET << 16; @@ -429,10 +430,10 @@ static int visorhba_bus_reset_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; shost_for_each_device(scsidev, scsidev->host) { vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc(&vdisk->error_count); else - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + seqnum32_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } rtn = forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsidev); if (rtn == SUCCESS) { @@ -803,9 +804,9 @@ static void do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, return; /* Okay see what our error_count is here.... */ vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { - atomic_inc(&vdisk->error_count); - atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + if (seqnum32_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { + seqnum32_inc(&vdisk->error_count); + seqnum32_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } } @@ -881,10 +882,10 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, kfree(buf); } else { vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->ios_threshold) > 0) { - atomic_dec(&vdisk->ios_threshold); - if (atomic_read(&vdisk->ios_threshold) == 0) - atomic_set(&vdisk->error_count, 0); + if (seqnum32_read(&vdisk->ios_threshold) > 0) { + seqnum32_dec(&vdisk->ios_threshold); + if (seqnum32_read(&vdisk->ios_threshold) == 0) + seqnum32_set(&vdisk->error_count, 0); } } } -- 2.27.0 From thierry.reding at gmail.com Tue Nov 10 20:29:45 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Tue, 10 Nov 2020 21:29:45 +0100 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201104234427.26477-12-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> Message-ID: <20201110202945.GF2375022@ulmo> On Thu, Nov 05, 2020 at 02:44:08AM +0300, Dmitry Osipenko wrote: > Add OPP and SoC core voltage scaling support to the display controller > driver. This is required for enabling system-wide DVFS on older Tegra > SoCs. > > Tested-by: Peter Geis > Tested-by: Nicolas Chauvet > Signed-off-by: Dmitry Osipenko > --- > drivers/gpu/drm/tegra/Kconfig | 1 + > drivers/gpu/drm/tegra/dc.c | 138 +++++++++++++++++++++++++++++++++- > drivers/gpu/drm/tegra/dc.h | 5 ++ > 3 files changed, 143 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig > index 1650a448eabd..9eec4c3fbd3b 100644 > --- a/drivers/gpu/drm/tegra/Kconfig > +++ b/drivers/gpu/drm/tegra/Kconfig > @@ -12,6 +12,7 @@ config DRM_TEGRA > select INTERCONNECT > select IOMMU_IOVA > select CEC_CORE if CEC_NOTIFIER > + select PM_OPP > help > Choose this option if you have an NVIDIA Tegra SoC. > > diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c > index fd7c8828652d..babcb66a335b 100644 > --- a/drivers/gpu/drm/tegra/dc.c > +++ b/drivers/gpu/drm/tegra/dc.c > @@ -11,9 +11,13 @@ > #include > #include > #include > +#include > #include > +#include > #include > > +#include > +#include > #include > > #include > @@ -1699,6 +1703,55 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc, > return 0; > } > > +static void tegra_dc_update_voltage_state(struct tegra_dc *dc, > + struct tegra_dc_state *state) > +{ > + struct dev_pm_opp *opp; > + unsigned long rate; > + int err, min_uV; > + > + /* OPP usage is optional */ > + if (!dc->opp_table) > + return; > + > + /* calculate actual pixel clock rate which depends on internal divider */ > + rate = DIV_ROUND_UP(clk_get_rate(dc->clk) * 2, state->div + 2); > + > + /* find suitable OPP for the rate */ > + opp = dev_pm_opp_find_freq_ceil(dc->dev, &rate); > + > + if (opp == ERR_PTR(-ERANGE)) > + opp = dev_pm_opp_find_freq_floor(dc->dev, &rate); > + > + if (IS_ERR(opp)) { > + dev_err(dc->dev, "failed to find OPP for %lu Hz: %ld\n", > + rate, PTR_ERR(opp)); > + return; > + } > + > + min_uV = dev_pm_opp_get_voltage(opp); > + dev_pm_opp_put(opp); > + > + /* > + * Voltage scaling is optional and trying to set voltage for a dummy > + * regulator will error out. > + */ > + if (!device_property_present(dc->dev, "core-supply")) > + return; This is a potentially heavy operation, so I think we should avoid that here. How about you use devm_regulator_get_optional() in ->probe()? That returns -ENODEV if no regulator was specified, in which case you can set dc->core_reg = NULL and use that as the condition here. > + > + /* > + * Note that the minimum core voltage depends on the pixel clock > + * rate (which depends on internal clock divider of CRTC) and not on > + * the rate of the display controller clock. This is why we're not > + * using dev_pm_opp_set_rate() API and instead are managing the > + * voltage by ourselves. > + */ > + err = regulator_set_voltage(dc->core_reg, min_uV, INT_MAX); > + if (err) > + dev_err(dc->dev, "failed to set CORE voltage to %duV: %d\n", > + min_uV, err); > +} Also, I'd prefer if the flow here was more linear, such as: if (dc->core_reg) { err = regulator_set_voltage(...); ... } > + > static void tegra_dc_commit_state(struct tegra_dc *dc, > struct tegra_dc_state *state) > { > @@ -1738,6 +1791,8 @@ static void tegra_dc_commit_state(struct tegra_dc *dc, > if (err < 0) > dev_err(dc->dev, "failed to set clock %pC to %lu Hz: %d\n", > dc->clk, state->pclk, err); > + > + tegra_dc_update_voltage_state(dc, state); > } > > static void tegra_dc_stop(struct tegra_dc *dc) > @@ -2521,6 +2576,7 @@ static int tegra_dc_runtime_suspend(struct host1x_client *client) > > clk_disable_unprepare(dc->clk); > pm_runtime_put_sync(dev); > + regulator_disable(dc->core_reg); > > return 0; > } > @@ -2531,10 +2587,16 @@ static int tegra_dc_runtime_resume(struct host1x_client *client) > struct device *dev = client->dev; > int err; > > + err = regulator_enable(dc->core_reg); > + if (err < 0) { > + dev_err(dev, "failed to enable CORE regulator: %d\n", err); > + return err; > + } > + > err = pm_runtime_get_sync(dev); > if (err < 0) { > dev_err(dev, "failed to get runtime PM: %d\n", err); > - return err; > + goto disable_regulator; > } > > if (dc->soc->has_powergate) { > @@ -2564,6 +2626,9 @@ static int tegra_dc_runtime_resume(struct host1x_client *client) > clk_disable_unprepare(dc->clk); > put_rpm: > pm_runtime_put_sync(dev); > +disable_regulator: > + regulator_disable(dc->core_reg); > + > return err; > } > > @@ -2879,6 +2944,72 @@ static int tegra_dc_couple(struct tegra_dc *dc) > return 0; > } > > +static void tegra_dc_deinit_opp_table(void *data) > +{ > + struct tegra_dc *dc = data; > + > + dev_pm_opp_of_remove_table(dc->dev); > + dev_pm_opp_put_supported_hw(dc->opp_table); > + dev_pm_opp_put_regulators(dc->opp_table); > +} > + > +static int devm_tegra_dc_opp_table_init(struct tegra_dc *dc) > +{ > + struct opp_table *hw_opp_table; > + u32 hw_version; > + int err; > + > + /* voltage scaling is optional */ > + dc->core_reg = devm_regulator_get(dc->dev, "core"); > + if (IS_ERR(dc->core_reg)) > + return dev_err_probe(dc->dev, PTR_ERR(dc->core_reg), > + "failed to get CORE regulator\n"); > + > + /* legacy device-trees don't have OPP table */ > + if (!device_property_present(dc->dev, "operating-points-v2")) > + return 0; "Legacy" is a bit confusing here. For one, no device trees currently have these tables and secondly, for newer SoCs we may never need them. > + > + dc->opp_table = dev_pm_opp_get_opp_table(dc->dev); > + if (IS_ERR(dc->opp_table)) > + return dev_err_probe(dc->dev, PTR_ERR(dc->opp_table), > + "failed to prepare OPP table\n"); > + > + if (of_machine_is_compatible("nvidia,tegra20")) > + hw_version = BIT(tegra_sku_info.soc_process_id); > + else > + hw_version = BIT(tegra_sku_info.soc_speedo_id); > + > + hw_opp_table = dev_pm_opp_set_supported_hw(dc->dev, &hw_version, 1); > + err = PTR_ERR_OR_ZERO(hw_opp_table); What's the point of this? A more canonical version would be: if (IS_ERR(hw_opp_table)) { err = PTR_ERR(hw_opp_table); dev_err(dc->dev, ...); goto put_table; } That uses the same number of lines but is much easier to read, in my opinion, because it is the canonical form. > + if (err) { > + dev_err(dc->dev, "failed to set supported HW: %d\n", err); > + goto put_table; > + } > + > + err = dev_pm_opp_of_add_table(dc->dev); > + if (err) { > + dev_err(dc->dev, "failed to add OPP table: %d\n", err); > + goto put_hw; > + } > + > + err = devm_add_action(dc->dev, tegra_dc_deinit_opp_table, dc); > + if (err) > + goto remove_table; Do these functions return positive values? If not, I'd prefer if this check was more explicit (i.e. err < 0) for consistency with the rest of this code. > + > + dev_info(dc->dev, "OPP HW ver. 0x%x\n", hw_version); > + > + return 0; > + > +remove_table: > + dev_pm_opp_of_remove_table(dc->dev); > +put_hw: > + dev_pm_opp_put_supported_hw(dc->opp_table); > +put_table: > + dev_pm_opp_put_opp_table(dc->opp_table); > + > + return err; > +} > + > static int tegra_dc_probe(struct platform_device *pdev) > { > struct tegra_dc *dc; > @@ -2937,6 +3068,10 @@ static int tegra_dc_probe(struct platform_device *pdev) > tegra_powergate_power_off(dc->powergate); > } > > + err = devm_tegra_dc_opp_table_init(dc); > + if (err < 0) > + return err; > + > dc->regs = devm_platform_ioremap_resource(pdev, 0); > if (IS_ERR(dc->regs)) > return PTR_ERR(dc->regs); > @@ -3007,6 +3142,7 @@ struct platform_driver tegra_dc_driver = { > .driver = { > .name = "tegra-dc", > .of_match_table = tegra_dc_of_match, > + .sync_state = tegra_soc_device_sync_state, > }, > .probe = tegra_dc_probe, > .remove = tegra_dc_remove, > diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h > index ba4ed35139fb..fd774fc5c2e4 100644 > --- a/drivers/gpu/drm/tegra/dc.h > +++ b/drivers/gpu/drm/tegra/dc.h > @@ -13,6 +13,8 @@ > > #include "drm.h" > > +struct opp_table; > +struct regulator; > struct tegra_output; > > #define TEGRA_DC_LEGACY_PLANES_NUM 6 > @@ -107,6 +109,9 @@ struct tegra_dc { > struct drm_info_list *debugfs_files; > > const struct tegra_dc_soc_info *soc; > + > + struct opp_table *opp_table; > + struct regulator *core_reg; We typically use a _supply suffix on regulators to avoid confusing this with "register". Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From broonie at kernel.org Tue Nov 10 20:32:57 2020 From: broonie at kernel.org (Mark Brown) Date: Tue, 10 Nov 2020 20:32:57 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201110202945.GF2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> Message-ID: <20201110203257.GC5957@sirena.org.uk> On Tue, Nov 10, 2020 at 09:29:45PM +0100, Thierry Reding wrote: > On Thu, Nov 05, 2020 at 02:44:08AM +0300, Dmitry Osipenko wrote: > > + /* > > + * Voltage scaling is optional and trying to set voltage for a dummy > > + * regulator will error out. > > + */ > > + if (!device_property_present(dc->dev, "core-supply")) > > + return; > This is a potentially heavy operation, so I think we should avoid that > here. How about you use devm_regulator_get_optional() in ->probe()? That > returns -ENODEV if no regulator was specified, in which case you can set > dc->core_reg = NULL and use that as the condition here. Or enumerate the configurable voltages after getting the regulator and handle that appropriately which would be more robust in case there's missing or unusual constraints. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From gregkh at linuxfoundation.org Tue Nov 10 20:42:21 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Tue, 10 Nov 2020 21:42:21 +0100 Subject: [PATCH 12/13] drivers/staging/unisys/visorhba: convert stats to use seqnum_ops In-Reply-To: <6fb679d23de785bbd1be6a528127e29f8ee6abd7.1605027593.git.skhan@linuxfoundation.org> References: <6fb679d23de785bbd1be6a528127e29f8ee6abd7.1605027593.git.skhan@linuxfoundation.org> Message-ID: On Tue, Nov 10, 2020 at 12:53:38PM -0700, Shuah Khan wrote: > seqnum_ops api is introduced to be used when a variable is used as > a sequence/stat counter and doesn't guard object lifetimes. This > clearly differentiates atomic_t usages that guard object lifetimes. > > seqnum32 variables wrap around to INT_MIN when it overflows and > should not be used to guard resource lifetimes, device usage and > open counts that control state changes, and pm states. > > atomic_t variables used for error_count and ios_threshold are atomic > counters and guarded by max. values. No change to the behavior with > this change. > > Signed-off-by: Shuah Khan > --- > .../staging/unisys/visorhba/visorhba_main.c | 37 ++++++++++--------- > 1 file changed, 19 insertions(+), 18 deletions(-) > > diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c > index 7ae5306b92fe..3209958b8aaa 100644 > --- a/drivers/staging/unisys/visorhba/visorhba_main.c > +++ b/drivers/staging/unisys/visorhba/visorhba_main.c > @@ -10,6 +10,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -41,8 +42,8 @@ MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR); > struct visordisk_info { > struct scsi_device *sdev; > u32 valid; > - atomic_t ios_threshold; > - atomic_t error_count; > + struct seqnum32 ios_threshold; > + struct seqnum32 error_count; Are you sure the threshold variable is a sequence number? It goes up and down, not just up and up and up. An error count just goes up :) thanks, greg k-h From thierry.reding at gmail.com Tue Nov 10 20:47:27 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Tue, 10 Nov 2020 21:47:27 +0100 Subject: [PATCH v1 07/30] soc/tegra: Add sync state API In-Reply-To: <20201104234427.26477-8-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-8-digetx@gmail.com> Message-ID: <20201110204727.GG2375022@ulmo> On Thu, Nov 05, 2020 at 02:44:04AM +0300, Dmitry Osipenko wrote: > Introduce sync state API that will be used by Tegra device drivers. This > new API is primarily needed for syncing state of SoC devices that are left > ON after bootloader or permanently enabled. All these devices belong to a > shared CORE voltage domain, and thus, we needed to bring all the devices > into expected state before the voltage scaling could be performed. > > All drivers of DVFS-critical devices shall sync theirs the state before > Tegra's voltage regulator coupler will be allowed to perform a system-wide > voltage scaling. > > Tested-by: Peter Geis > Tested-by: Nicolas Chauvet > Signed-off-by: Dmitry Osipenko > --- > drivers/soc/tegra/common.c | 152 ++++++++++++++++++++++++++++++++++++- > include/soc/tegra/common.h | 22 ++++++ > 2 files changed, 170 insertions(+), 4 deletions(-) > > diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c > index 3dc54f59cafe..f9b2b6f57887 100644 > --- a/drivers/soc/tegra/common.c > +++ b/drivers/soc/tegra/common.c > @@ -3,13 +3,52 @@ > * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved. > */ > > +#define dev_fmt(fmt) "%s: " fmt, __func__ > +#define pr_fmt(fmt) "%s: " fmt, __func__ > + > +#include > +#include > +#include > #include > +#include > > #include > > +#define terga_soc_for_each_device(__dev) \ tegra_soc_for_each_device > + for ((__dev) = tegra_soc_devices; (__dev) && (__dev)->compatible; \ > + (__dev)++) > + > +struct tegra_soc_device { > + const char *compatible; > + const bool dvfs_critical; > + unsigned int sync_count; > +}; > + > +static DEFINE_MUTEX(tegra_soc_lock); > +static struct tegra_soc_device *tegra_soc_devices; > + > +/* > + * DVFS-critical devices are either active at a boot time or permanently > + * active, like EMC for example. System-wide DVFS should be deferred until > + * drivers of the critical devices synced theirs state. > + */ > + > +static struct tegra_soc_device tegra20_soc_devices[] = { > + { .compatible = "nvidia,tegra20-dc", .dvfs_critical = true, }, > + { .compatible = "nvidia,tegra20-emc", .dvfs_critical = true, }, > + { } > +}; > + > +static struct tegra_soc_device tegra30_soc_devices[] = { > + { .compatible = "nvidia,tegra30-dc", .dvfs_critical = true, }, > + { .compatible = "nvidia,tegra30-emc", .dvfs_critical = true, }, > + { .compatible = "nvidia,tegra30-pwm", .dvfs_critical = true, }, > + { } > +}; > + > static const struct of_device_id tegra_machine_match[] = { > - { .compatible = "nvidia,tegra20", }, > - { .compatible = "nvidia,tegra30", }, > + { .compatible = "nvidia,tegra20", .data = tegra20_soc_devices, }, > + { .compatible = "nvidia,tegra30", .data = tegra30_soc_devices, }, > { .compatible = "nvidia,tegra114", }, > { .compatible = "nvidia,tegra124", }, > { .compatible = "nvidia,tegra132", }, > @@ -17,7 +56,7 @@ static const struct of_device_id tegra_machine_match[] = { > { } > }; > > -bool soc_is_tegra(void) > +static const struct of_device_id *tegra_soc_of_match(void) > { > const struct of_device_id *match; > struct device_node *root; > @@ -29,5 +68,110 @@ bool soc_is_tegra(void) > match = of_match_node(tegra_machine_match, root); > of_node_put(root); > > - return match != NULL; > + return match; > +} > + > +bool soc_is_tegra(void) > +{ > + return tegra_soc_of_match() != NULL; > +} > + > +void tegra_soc_device_sync_state(struct device *dev) > +{ > + struct tegra_soc_device *soc_dev; > + > + mutex_lock(&tegra_soc_lock); > + terga_soc_for_each_device(soc_dev) { tegra_soc_for_each_device > + if (!of_device_is_compatible(dev->of_node, soc_dev->compatible)) > + continue; > + > + if (!soc_dev->sync_count) { > + dev_err(dev, "already synced\n"); > + break; > + } > + > + /* > + * All DVFS-capable devices should have the CORE regulator > + * phandle. Older device-trees don't have it, hence state > + * won't be synced for the older DTBs, allowing them to work > + * properly. > + */ > + if (soc_dev->dvfs_critical && > + !device_property_present(dev, "core-supply")) { > + dev_dbg(dev, "doesn't have core supply\n"); > + break; > + } > + > + soc_dev->sync_count--; > + dev_dbg(dev, "sync_count=%u\n", soc_dev->sync_count); > + break; > + } > + mutex_unlock(&tegra_soc_lock); > +} > +EXPORT_SYMBOL_GPL(tegra_soc_device_sync_state); > + > +bool tegra_soc_dvfs_state_synced(void) > +{ > + struct tegra_soc_device *soc_dev; > + bool synced_state = true; > + > + /* > + * CORE voltage scaling is limited until drivers of the critical > + * devices synced theirs state. > + */ > + mutex_lock(&tegra_soc_lock); > + terga_soc_for_each_device(soc_dev) { tegra_soc_for_each_device I wonder if you copy/pasted this or if you got really lucky to mistype this all three times. > + if (!soc_dev->sync_count || !soc_dev->dvfs_critical) > + continue; > + > + pr_debug_ratelimited("%s: sync_count=%u\n", > + soc_dev->compatible, soc_dev->sync_count); > + > + synced_state = false; > + break; > + } > + mutex_unlock(&tegra_soc_lock); > + > + return synced_state; > +} > + > +static int __init tegra_soc_devices_init(void) > +{ > + struct device_node *np, *prev_np = NULL; > + struct tegra_soc_device *soc_dev; > + const struct of_device_id *match; > + > + if (!soc_is_tegra()) > + return 0; > + > + match = tegra_soc_of_match(); > + tegra_soc_devices = (void *)match->data; > + > + /* > + * If device node is disabled in a device-tree, then we shouldn't > + * care about this device. Even if device is active during boot, > + * its clock will be disabled by CCF as unused. > + */ > + terga_soc_for_each_device(soc_dev) { > + do { > + /* > + * Devices like display controller have multiple > + * instances with the same compatible. Hence we need > + * to walk up the whole tree in order to account those > + * multiple instances. > + */ > + np = of_find_compatible_node(prev_np, NULL, > + soc_dev->compatible); > + of_node_put(prev_np); > + prev_np = np; > + > + if (of_device_is_available(np)) { > + pr_debug("added %s\n", soc_dev->compatible); > + soc_dev->sync_count++; > + } > + } while (np); Maybe use for_each_compatible_node() for that inside loop? > + } > + > + return 0; > } > +postcore_initcall_sync(tegra_soc_devices_init); This is unfortunate. I recall having this discussion multiple times and one idea that has been floating around for a while was to let a driver bind against the top-level "bus" node. That has the advantage that it both anchors the code somewhere, so we don't have to play this game of checking for the SoC with soc_is_tegra(), and it properly orders this with respect to the child devices, so we wouldn't have to make this a postcore_initcall. Might be worth looking at that again, but for now this seems okay. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From thierry.reding at gmail.com Tue Nov 10 20:50:57 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Tue, 10 Nov 2020 21:50:57 +0100 Subject: [PATCH v1 18/30] pwm: tegra: Support OPP and core voltage scaling In-Reply-To: <20201104234427.26477-19-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-19-digetx@gmail.com> Message-ID: <20201110205057.GH2375022@ulmo> On Thu, Nov 05, 2020 at 02:44:15AM +0300, Dmitry Osipenko wrote: [...] > +static void tegra_pwm_deinit_opp_table(void *data) > +{ > + struct device *dev = data; > + struct opp_table *opp_table; > + > + opp_table = dev_pm_opp_get_opp_table(dev); > + dev_pm_opp_of_remove_table(dev); > + dev_pm_opp_put_regulators(opp_table); > + dev_pm_opp_put_opp_table(opp_table); > +} > + > +static int devm_tegra_pwm_init_opp_table(struct device *dev) > +{ > + struct opp_table *opp_table; > + const char *rname = "core"; > + int err; > + > + /* voltage scaling is optional */ > + if (device_property_present(dev, "core-supply")) > + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); > + else > + opp_table = dev_pm_opp_get_opp_table(dev); > + > + if (IS_ERR(opp_table)) > + return dev_err_probe(dev, PTR_ERR(opp_table), > + "failed to prepare OPP table\n"); > + > + /* > + * OPP table presence is optional and we want the set_rate() of OPP > + * API to work similarly to clk_set_rate() if table is missing in a > + * device-tree. The add_table() errors out if OPP is missing in DT. > + */ > + if (device_property_present(dev, "operating-points-v2")) { > + err = dev_pm_opp_of_add_table(dev); > + if (err) { > + dev_err(dev, "failed to add OPP table: %d\n", err); > + goto put_table; > + } > + } > + > + err = devm_add_action(dev, tegra_pwm_deinit_opp_table, dev); > + if (err) > + goto remove_table; > + > + return 0; > + > +remove_table: > + dev_pm_opp_of_remove_table(dev); > +put_table: > + dev_pm_opp_put_regulators(opp_table); > + > + return err; > +} These two functions seem to be heavily boilerplate across all these drivers. Have you considered splitting these out into separate helpers? Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From skhan at linuxfoundation.org Tue Nov 10 21:02:14 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Tue, 10 Nov 2020 14:02:14 -0700 Subject: [PATCH 12/13] drivers/staging/unisys/visorhba: convert stats to use seqnum_ops In-Reply-To: References: <6fb679d23de785bbd1be6a528127e29f8ee6abd7.1605027593.git.skhan@linuxfoundation.org> Message-ID: <82a5ad26-a633-bf76-0591-14f803133666@linuxfoundation.org> On 11/10/20 1:42 PM, Greg KH wrote: > On Tue, Nov 10, 2020 at 12:53:38PM -0700, Shuah Khan wrote: >> seqnum_ops api is introduced to be used when a variable is used as >> a sequence/stat counter and doesn't guard object lifetimes. This >> clearly differentiates atomic_t usages that guard object lifetimes. >> >> seqnum32 variables wrap around to INT_MIN when it overflows and >> should not be used to guard resource lifetimes, device usage and >> open counts that control state changes, and pm states. >> >> atomic_t variables used for error_count and ios_threshold are atomic >> counters and guarded by max. values. No change to the behavior with >> this change. >> >> Signed-off-by: Shuah Khan >> --- >> .../staging/unisys/visorhba/visorhba_main.c | 37 ++++++++++--------- >> 1 file changed, 19 insertions(+), 18 deletions(-) >> >> diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c >> index 7ae5306b92fe..3209958b8aaa 100644 >> --- a/drivers/staging/unisys/visorhba/visorhba_main.c >> +++ b/drivers/staging/unisys/visorhba/visorhba_main.c >> @@ -10,6 +10,7 @@ >> #include >> #include >> #include >> +#include >> #include >> #include >> #include >> @@ -41,8 +42,8 @@ MODULE_ALIAS("visorbus:" VISOR_VHBA_CHANNEL_GUID_STR); >> struct visordisk_info { >> struct scsi_device *sdev; >> u32 valid; >> - atomic_t ios_threshold; >> - atomic_t error_count; >> + struct seqnum32 ios_threshold; >> + struct seqnum32 error_count; > > Are you sure the threshold variable is a sequence number > > It goes up and down, not just up and up and up. Right. I does go down. Turns out this is the only place seqnum32_dec() is used. :) I will fix. I noticed you made a comment about _dec() interfaces on 1/13. I can drop those as well. This way seqnum_ops can be just used for up counters. thanks, -- Shuah From digetx at gmail.com Tue Nov 10 21:17:04 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:17:04 +0300 Subject: [PATCH v1 18/30] pwm: tegra: Support OPP and core voltage scaling In-Reply-To: <20201110205057.GH2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-19-digetx@gmail.com> <20201110205057.GH2375022@ulmo> Message-ID: 10.11.2020 23:50, Thierry Reding ?????: > On Thu, Nov 05, 2020 at 02:44:15AM +0300, Dmitry Osipenko wrote: > [...] >> +static void tegra_pwm_deinit_opp_table(void *data) >> +{ >> + struct device *dev = data; >> + struct opp_table *opp_table; >> + >> + opp_table = dev_pm_opp_get_opp_table(dev); >> + dev_pm_opp_of_remove_table(dev); >> + dev_pm_opp_put_regulators(opp_table); >> + dev_pm_opp_put_opp_table(opp_table); >> +} >> + >> +static int devm_tegra_pwm_init_opp_table(struct device *dev) >> +{ >> + struct opp_table *opp_table; >> + const char *rname = "core"; >> + int err; >> + >> + /* voltage scaling is optional */ >> + if (device_property_present(dev, "core-supply")) >> + opp_table = dev_pm_opp_set_regulators(dev, &rname, 1); >> + else >> + opp_table = dev_pm_opp_get_opp_table(dev); >> + >> + if (IS_ERR(opp_table)) >> + return dev_err_probe(dev, PTR_ERR(opp_table), >> + "failed to prepare OPP table\n"); >> + >> + /* >> + * OPP table presence is optional and we want the set_rate() of OPP >> + * API to work similarly to clk_set_rate() if table is missing in a >> + * device-tree. The add_table() errors out if OPP is missing in DT. >> + */ >> + if (device_property_present(dev, "operating-points-v2")) { >> + err = dev_pm_opp_of_add_table(dev); >> + if (err) { >> + dev_err(dev, "failed to add OPP table: %d\n", err); >> + goto put_table; >> + } >> + } >> + >> + err = devm_add_action(dev, tegra_pwm_deinit_opp_table, dev); >> + if (err) >> + goto remove_table; >> + >> + return 0; >> + >> +remove_table: >> + dev_pm_opp_of_remove_table(dev); >> +put_table: >> + dev_pm_opp_put_regulators(opp_table); >> + >> + return err; >> +} > > These two functions seem to be heavily boilerplate across all these > drivers. Have you considered splitting these out into separate helpers? The helper is already prepared for v2. From digetx at gmail.com Tue Nov 10 21:17:30 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:17:30 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201110202945.GF2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> Message-ID: <6bbec0aa-732a-2feb-684a-b1d8cc6a0471@gmail.com> 10.11.2020 23:29, Thierry Reding ?????: >> + >> + dc->opp_table = dev_pm_opp_get_opp_table(dc->dev); >> + if (IS_ERR(dc->opp_table)) >> + return dev_err_probe(dc->dev, PTR_ERR(dc->opp_table), >> + "failed to prepare OPP table\n"); >> + >> + if (of_machine_is_compatible("nvidia,tegra20")) >> + hw_version = BIT(tegra_sku_info.soc_process_id); >> + else >> + hw_version = BIT(tegra_sku_info.soc_speedo_id); >> + >> + hw_opp_table = dev_pm_opp_set_supported_hw(dc->dev, &hw_version, 1); >> + err = PTR_ERR_OR_ZERO(hw_opp_table); > What's the point of this? A more canonical version would be: > > if (IS_ERR(hw_opp_table)) { > err = PTR_ERR(hw_opp_table); > dev_err(dc->dev, ...); > goto put_table; > } > > That uses the same number of lines but is much easier to read, in my > opinion, because it is the canonical form. > Your variant is much more difficult to read for me :/ I guess the only reason it could be "canonical" is because PTR_ERR_OR_ZERO was added not so long time ago. But don't worry, this code will be moved out in a v2 and it won't use PTR_ERR_OR_ZERO. From digetx at gmail.com Tue Nov 10 21:22:34 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:22:34 +0300 Subject: [PATCH v1 07/30] soc/tegra: Add sync state API In-Reply-To: <20201110204727.GG2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-8-digetx@gmail.com> <20201110204727.GG2375022@ulmo> Message-ID: <71934373-8425-345b-7719-0903f846119f@gmail.com> 10.11.2020 23:47, Thierry Reding ?????: ... > tegra_soc_for_each_device > > I wonder if you copy/pasted this or if you got really lucky to mistype > this all three times. Copied of course :) I added a special spell checking rule for this typo, but it does help reliably. ... >> + terga_soc_for_each_device(soc_dev) { >> + do { >> + /* >> + * Devices like display controller have multiple >> + * instances with the same compatible. Hence we need >> + * to walk up the whole tree in order to account those >> + * multiple instances. >> + */ >> + np = of_find_compatible_node(prev_np, NULL, >> + soc_dev->compatible); >> + of_node_put(prev_np); >> + prev_np = np; >> + >> + if (of_device_is_available(np)) { >> + pr_debug("added %s\n", soc_dev->compatible); >> + soc_dev->sync_count++; >> + } >> + } while (np); > > Maybe use for_each_compatible_node() for that inside loop? Good point! I think there is actually an of_node_put() bug in current variant, which for_each_compatible_node() would safe from. >> + } >> + >> + return 0; >> } >> +postcore_initcall_sync(tegra_soc_devices_init); > > This is unfortunate. I recall having this discussion multiple times and > one idea that has been floating around for a while was to let a driver > bind against the top-level "bus" node. That has the advantage that it > both anchors the code somewhere, so we don't have to play this game of > checking for the SoC with soc_is_tegra(), and it properly orders this > with respect to the child devices, so we wouldn't have to make this a > postcore_initcall. > > Might be worth looking at that again, but for now this seems okay. Thanks From digetx at gmail.com Tue Nov 10 21:23:41 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:23:41 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201110203257.GC5957@sirena.org.uk> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> Message-ID: <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> 10.11.2020 23:32, Mark Brown ?????: > On Tue, Nov 10, 2020 at 09:29:45PM +0100, Thierry Reding wrote: >> On Thu, Nov 05, 2020 at 02:44:08AM +0300, Dmitry Osipenko wrote: > >>> + /* >>> + * Voltage scaling is optional and trying to set voltage for a dummy >>> + * regulator will error out. >>> + */ >>> + if (!device_property_present(dc->dev, "core-supply")) >>> + return; > >> This is a potentially heavy operation, so I think we should avoid that >> here. How about you use devm_regulator_get_optional() in ->probe()? That >> returns -ENODEV if no regulator was specified, in which case you can set >> dc->core_reg = NULL and use that as the condition here. > > Or enumerate the configurable voltages after getting the regulator and > handle that appropriately which would be more robust in case there's > missing or unusual constraints. > I already changed that code to use regulator_get_optional() for v2. Regarding the enumerating supported voltage.. I think this should be done by the OPP core, but regulator core doesn't work well if regulator_get() is invoked more than one time for the same device, at least there is a loud debugfs warning about an already existing directory for a regulator. It's easy to check whether the debug directory exists before creating it, like thermal framework does it for example, but then there were some other more difficult issues.. I don't recall what they were right now. Perhaps will be easier to simply get a error from regulator_set_voltage() for now because it shouldn't ever happen in practice, unless device-tree has wrong constraints. From digetx at gmail.com Tue Nov 10 21:32:27 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:32:27 +0300 Subject: [PATCH v1 07/30] soc/tegra: Add sync state API In-Reply-To: <71934373-8425-345b-7719-0903f846119f@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-8-digetx@gmail.com> <20201110204727.GG2375022@ulmo> <71934373-8425-345b-7719-0903f846119f@gmail.com> Message-ID: <7b6c7c62-495c-eeb8-9cdb-0c33be653e3d@gmail.com> 11.11.2020 00:22, Dmitry Osipenko ?????: > I added a special spell checking rule for this typo, but it does help > reliably. does *not* From digetx at gmail.com Tue Nov 10 21:50:38 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Wed, 11 Nov 2020 00:50:38 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201110202945.GF2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> Message-ID: <7b0052e1-0ea7-b28f-ae46-52e669a980ac@gmail.com> 10.11.2020 23:29, Thierry Reding ?????: >> + /* legacy device-trees don't have OPP table */ >> + if (!device_property_present(dc->dev, "operating-points-v2")) >> + return 0; > "Legacy" is a bit confusing here. For one, no device trees currently > have these tables and secondly, for newer SoCs we may never need them. > I had the same thought and already improved such comments a day ago. From jernej.skrabec at siol.net Tue Nov 10 22:35:40 2020 From: jernej.skrabec at siol.net (Jernej Skrabec) Date: Tue, 10 Nov 2020 23:35:40 +0100 Subject: [PATCH v3] media: cedrus: Add support for VP8 decoding Message-ID: <20201110223540.4105284-1-jernej.skrabec@siol.net> VP8 in Cedrus shares same engine as H264. Note that it seems necessary to call bitstream parsing functions, to parse frame header, otherwise decoded image is garbage. This is contrary to what is driver supposed to do. However, values are not really used, so this might be acceptable. It's possible that bitstream parsing functions set some internal VPU state, which is later necessary for proper decoding. Biggest suspect is "VP8 probs update" trigger. Signed-off-by: Jernej Skrabec [addressed issues from reviewer] Signed-off-by: Emmanuel Gil Peyrot --- Changes in v3: - addressed comments from Ezequiel Garcia - new comments, using new macros from VP8 UAPI, new function for waiting on bit to be set Changes in v2: - rebased on top of current linux-media master branch NOTE: This now depends on following patch: https://patchwork.linuxtv.org/project/linux-media/patch/20201108202021.4187-1-linkmauve at linkmauve.fr/ drivers/staging/media/sunxi/cedrus/Makefile | 3 +- drivers/staging/media/sunxi/cedrus/cedrus.c | 8 + drivers/staging/media/sunxi/cedrus/cedrus.h | 24 + .../staging/media/sunxi/cedrus/cedrus_dec.c | 5 + .../staging/media/sunxi/cedrus/cedrus_hw.c | 2 + .../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++ .../staging/media/sunxi/cedrus/cedrus_video.c | 9 + .../staging/media/sunxi/cedrus/cedrus_vp8.c | 907 ++++++++++++++++++ 8 files changed, 1037 insertions(+), 1 deletion(-) create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c diff --git a/drivers/staging/media/sunxi/cedrus/Makefile b/drivers/staging/media/sunxi/cedrus/Makefile index 1bce49d3e7e2..a647b3690bf8 100644 --- a/drivers/staging/media/sunxi/cedrus/Makefile +++ b/drivers/staging/media/sunxi/cedrus/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_VIDEO_SUNXI_CEDRUS) += sunxi-cedrus.o sunxi-cedrus-y = cedrus.o cedrus_video.o cedrus_hw.o cedrus_dec.o \ - cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o + cedrus_mpeg2.o cedrus_h264.o cedrus_h265.o \ + cedrus_vp8.o diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 9a102b7c1bb9..0b8e748ef8f1 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -142,6 +142,13 @@ static const struct cedrus_control cedrus_controls[] = { .codec = CEDRUS_CODEC_H265, .required = false, }, + { + .cfg = { + .id = V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER, + }, + .codec = CEDRUS_CODEC_VP8, + .required = true, + }, }; #define CEDRUS_CONTROLS_COUNT ARRAY_SIZE(cedrus_controls) @@ -393,6 +400,7 @@ static int cedrus_probe(struct platform_device *pdev) dev->dec_ops[CEDRUS_CODEC_MPEG2] = &cedrus_dec_ops_mpeg2; dev->dec_ops[CEDRUS_CODEC_H264] = &cedrus_dec_ops_h264; dev->dec_ops[CEDRUS_CODEC_H265] = &cedrus_dec_ops_h265; + dev->dec_ops[CEDRUS_CODEC_VP8] = &cedrus_dec_ops_vp8; mutex_init(&dev->dev_mutex); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 93c843ae14bb..fece505272b4 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -22,6 +22,7 @@ #include #include +#include #include #define CEDRUS_NAME "cedrus" @@ -35,6 +36,7 @@ enum cedrus_codec { CEDRUS_CODEC_MPEG2, CEDRUS_CODEC_H264, CEDRUS_CODEC_H265, + CEDRUS_CODEC_VP8, CEDRUS_CODEC_LAST, }; @@ -76,6 +78,10 @@ struct cedrus_h265_run { const struct v4l2_ctrl_hevc_slice_params *slice_params; }; +struct cedrus_vp8_run { + const struct v4l2_ctrl_vp8_frame_header *frame_params; +}; + struct cedrus_run { struct vb2_v4l2_buffer *src; struct vb2_v4l2_buffer *dst; @@ -84,6 +90,7 @@ struct cedrus_run { struct cedrus_h264_run h264; struct cedrus_mpeg2_run mpeg2; struct cedrus_h265_run h265; + struct cedrus_vp8_run vp8; }; }; @@ -135,6 +142,14 @@ struct cedrus_ctx { void *neighbor_info_buf; dma_addr_t neighbor_info_buf_addr; } h265; + struct { + unsigned int last_frame_p_type; + unsigned int last_filter_type; + unsigned int last_sharpness_level; + + u8 *entropy_probs_buf; + dma_addr_t entropy_probs_buf_dma; + } vp8; } codec; }; @@ -181,6 +196,7 @@ struct cedrus_dev { extern struct cedrus_dec_ops cedrus_dec_ops_mpeg2; extern struct cedrus_dec_ops cedrus_dec_ops_h264; extern struct cedrus_dec_ops cedrus_dec_ops_h265; +extern struct cedrus_dec_ops cedrus_dec_ops_vp8; static inline void cedrus_write(struct cedrus_dev *dev, u32 reg, u32 val) { @@ -192,6 +208,14 @@ static inline u32 cedrus_read(struct cedrus_dev *dev, u32 reg) return readl(dev->base + reg); } +static inline u32 cedrus_wait_for(struct cedrus_dev *dev, u32 reg, u32 flag) +{ + u32 value; + + return readl_poll_timeout_atomic(dev->base + reg, value, + (value & flag) == 0, 10, 1000); +} + static inline dma_addr_t cedrus_buf_addr(struct vb2_buffer *buf, struct v4l2_pix_format *pix_fmt, unsigned int plane) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c index 6385026d1b6b..1810fb6cc8da 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_dec.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_dec.c @@ -70,6 +70,11 @@ void cedrus_device_run(void *priv) V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS); break; + case V4L2_PIX_FMT_VP8_FRAME: + run.vp8.frame_params = cedrus_find_control_data(ctx, + V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER); + break; + default: break; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index bcf050a04ffc..111cb91f8fc2 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -47,7 +47,9 @@ int cedrus_engine_enable(struct cedrus_ctx *ctx, enum cedrus_codec codec) reg |= VE_MODE_DEC_MPEG; break; + /* H.264 and VP8 both use the same decoding mode bit. */ case CEDRUS_CODEC_H264: + case CEDRUS_CODEC_VP8: reg |= VE_MODE_DEC_H264; break; diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h index 66b152f18d17..7718c561823f 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_regs.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus_regs.h @@ -546,6 +546,7 @@ #define VE_H264_SHS_QP_SCALING_MATRIX_DEFAULT BIT(24) #define VE_H264_CTRL 0x220 +#define VE_H264_CTRL_VP8 BIT(29) #define VE_H264_CTRL_VLD_DATA_REQ_INT BIT(2) #define VE_H264_CTRL_DECODE_ERR_INT BIT(1) #define VE_H264_CTRL_SLICE_DECODE_INT BIT(0) @@ -555,7 +556,12 @@ VE_H264_CTRL_SLICE_DECODE_INT) #define VE_H264_TRIGGER_TYPE 0x224 +#define VE_H264_TRIGGER_TYPE_PROBABILITY(x) SHIFT_AND_MASK_BITS(x, 31, 24) +#define VE_H264_TRIGGER_TYPE_BIN_LENS(x) SHIFT_AND_MASK_BITS((x) - 1, 18, 16) #define VE_H264_TRIGGER_TYPE_N_BITS(x) (((x) & 0x3f) << 8) +#define VE_H264_TRIGGER_TYPE_VP8_GET_BITS (15 << 0) +#define VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF (14 << 0) +#define VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE (10 << 0) #define VE_H264_TRIGGER_TYPE_AVC_SLICE_DECODE (8 << 0) #define VE_H264_TRIGGER_TYPE_INIT_SWDEC (7 << 0) #define VE_H264_TRIGGER_TYPE_FLUSH_BITS (3 << 0) @@ -565,6 +571,7 @@ #define VE_H264_STATUS_DECODE_ERR_INT VE_H264_CTRL_DECODE_ERR_INT #define VE_H264_STATUS_SLICE_DECODE_INT VE_H264_CTRL_SLICE_DECODE_INT #define VE_H264_STATUS_VLD_BUSY BIT(8) +#define VE_H264_STATUS_VP8_UPPROB_BUSY BIT(17) #define VE_H264_STATUS_INT_MASK VE_H264_CTRL_INT_MASK @@ -583,10 +590,83 @@ #define VE_H264_OUTPUT_FRAME_IDX 0x24c #define VE_H264_EXTRA_BUFFER1 0x250 #define VE_H264_EXTRA_BUFFER2 0x254 +#define VE_H264_MB_ADDR 0x260 +#define VE_H264_ERROR_CASE 0x2b8 #define VE_H264_BASIC_BITS 0x2dc #define VE_AVC_SRAM_PORT_OFFSET 0x2e0 #define VE_AVC_SRAM_PORT_DATA 0x2e4 +#define VE_VP8_PPS 0x214 +#define VE_VP8_PPS_PIC_TYPE_P_FRAME BIT(31) +#define VE_VP8_PPS_LAST_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 30, 28) +#define VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME BIT(27) +#define VE_VP8_PPS_ALTREF_SIGN_BIAS BIT(26) +#define VE_VP8_PPS_GOLDEN_SIGN_BIAS BIT(25) +#define VE_VP8_PPS_RELOAD_ENTROPY_PROBS BIT(24) +#define VE_VP8_PPS_REFRESH_ENTROPY_PROBS BIT(23) +#define VE_VP8_PPS_MB_NO_COEFF_SKIP BIT(22) +#define VE_VP8_PPS_TOKEN_PARTITION(v) SHIFT_AND_MASK_BITS(v, 21, 20) +#define VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE BIT(19) +#define VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE BIT(18) +#define VE_VP8_PPS_LOOP_FILTER_LEVEL(v) SHIFT_AND_MASK_BITS(v, 17, 12) +#define VE_VP8_PPS_LOOP_FILTER_SIMPLE BIT(11) +#define VE_VP8_PPS_SHARPNESS_LEVEL(v) SHIFT_AND_MASK_BITS(v, 10, 8) +#define VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE BIT(7) +#define VE_VP8_PPS_SEGMENTATION_ENABLE BIT(6) +#define VE_VP8_PPS_MB_SEGMENT_ABS_DELTA BIT(5) +#define VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP BIT(4) +#define VE_VP8_PPS_FULL_PIXEL BIT(3) +#define VE_VP8_PPS_BILINEAR_MC_FILTER BIT(2) +#define VE_VP8_PPS_FILTER_TYPE_SIMPLE BIT(1) +#define VE_VP8_PPS_LPF_DISABLE BIT(0) + +#define VE_VP8_QP_INDEX_DELTA 0x218 +#define VE_VP8_QP_INDEX_DELTA_UVAC(v) SHIFT_AND_MASK_BITS(v, 31, 27) +#define VE_VP8_QP_INDEX_DELTA_UVDC(v) SHIFT_AND_MASK_BITS(v, 26, 22) +#define VE_VP8_QP_INDEX_DELTA_Y2AC(v) SHIFT_AND_MASK_BITS(v, 21, 17) +#define VE_VP8_QP_INDEX_DELTA_Y2DC(v) SHIFT_AND_MASK_BITS(v, 16, 12) +#define VE_VP8_QP_INDEX_DELTA_Y1DC(v) SHIFT_AND_MASK_BITS(v, 11, 7) +#define VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(v) SHIFT_AND_MASK_BITS(v, 6, 0) + +#define VE_VP8_PART_SIZE_OFFSET 0x21c +#define VE_VP8_ENTROPY_PROBS_ADDR 0x250 +#define VE_VP8_FIRST_DATA_PART_LEN 0x254 + +#define VE_VP8_FSIZE 0x258 +#define VE_VP8_FSIZE_WIDTH(w) \ + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(w, 16), 15, 8) +#define VE_VP8_FSIZE_HEIGHT(h) \ + SHIFT_AND_MASK_BITS(DIV_ROUND_UP(h, 16), 7, 0) + +#define VE_VP8_PICSIZE 0x25c +#define VE_VP8_PICSIZE_WIDTH(w) SHIFT_AND_MASK_BITS(w, 27, 16) +#define VE_VP8_PICSIZE_HEIGHT(h) SHIFT_AND_MASK_BITS(h, 11, 0) + +#define VE_VP8_REC_LUMA 0x2ac +#define VE_VP8_FWD_LUMA 0x2b0 +#define VE_VP8_BWD_LUMA 0x2b4 +#define VE_VP8_REC_CHROMA 0x2d0 +#define VE_VP8_FWD_CHROMA 0x2d4 +#define VE_VP8_BWD_CHROMA 0x2d8 +#define VE_VP8_ALT_LUMA 0x2e8 +#define VE_VP8_ALT_CHROMA 0x2ec + +#define VE_VP8_SEGMENT_FEAT_MB_LV0 0x2f0 +#define VE_VP8_SEGMENT_FEAT_MB_LV1 0x2f4 + +#define VE_VP8_SEGMENT3(v) SHIFT_AND_MASK_BITS(v, 31, 24) +#define VE_VP8_SEGMENT2(v) SHIFT_AND_MASK_BITS(v, 23, 16) +#define VE_VP8_SEGMENT1(v) SHIFT_AND_MASK_BITS(v, 15, 8) +#define VE_VP8_SEGMENT0(v) SHIFT_AND_MASK_BITS(v, 7, 0) + +#define VE_VP8_REF_LF_DELTA 0x2f8 +#define VE_VP8_MODE_LF_DELTA 0x2fc + +#define VE_VP8_LF_DELTA3(v) SHIFT_AND_MASK_BITS(v, 30, 24) +#define VE_VP8_LF_DELTA2(v) SHIFT_AND_MASK_BITS(v, 22, 16) +#define VE_VP8_LF_DELTA1(v) SHIFT_AND_MASK_BITS(v, 14, 8) +#define VE_VP8_LF_DELTA0(v) SHIFT_AND_MASK_BITS(v, 6, 0) + #define VE_ISP_INPUT_SIZE 0xa00 #define VE_ISP_INPUT_STRIDE 0xa04 #define VE_ISP_CTRL 0xa08 diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 911f607d9b09..63d1c5c404ec 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -48,6 +48,10 @@ static struct cedrus_format cedrus_formats[] = { .directions = CEDRUS_DECODE_SRC, .capabilities = CEDRUS_CAPABILITY_H265_DEC, }, + { + .pixelformat = V4L2_PIX_FMT_VP8_FRAME, + .directions = CEDRUS_DECODE_SRC, + }, { .pixelformat = V4L2_PIX_FMT_SUNXI_TILED_NV12, .directions = CEDRUS_DECODE_DST, @@ -110,6 +114,7 @@ void cedrus_prepare_format(struct v4l2_pix_format *pix_fmt) case V4L2_PIX_FMT_MPEG2_SLICE: case V4L2_PIX_FMT_H264_SLICE: case V4L2_PIX_FMT_HEVC_SLICE: + case V4L2_PIX_FMT_VP8_FRAME: /* Zero bytes per line for encoded source. */ bytesperline = 0; /* Choose some minimum size since this can't be 0 */ @@ -473,6 +478,10 @@ static int cedrus_start_streaming(struct vb2_queue *vq, unsigned int count) ctx->current_codec = CEDRUS_CODEC_H265; break; + case V4L2_PIX_FMT_VP8_FRAME: + ctx->current_codec = CEDRUS_CODEC_VP8; + break; + default: return -EINVAL; } diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c new file mode 100644 index 000000000000..ff613ebd1180 --- /dev/null +++ b/drivers/staging/media/sunxi/cedrus/cedrus_vp8.c @@ -0,0 +1,907 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Cedrus VPU driver + * + * Copyright (c) 2019 Jernej Skrabec + */ + +/* + * VP8 in Cedrus shares same engine as H264. + * + * Note that it seems necessary to call bitstream parsing functions, + * to parse frame header, otherwise decoded image is garbage. This is + * contrary to what is driver supposed to do. However, values are not + * really used, so this might be acceptable. It's possible that bitstream + * parsing functions set some internal VPU state, which is later necessary + * for proper decoding. Biggest suspect is "VP8 probs update" trigger. + */ + +#include +#include + +#include + +#include "cedrus.h" +#include "cedrus_hw.h" +#include "cedrus_regs.h" + +#define CEDRUS_ENTROPY_PROBS_SIZE 0x2400 +#define VP8_PROB_HALF 128 +#define QUANT_DELTA_COUNT 5 + +/* + * This table comes from the concatenation of k_coeff_entropy_update_probs, + * kf_ymode_prob, default_mv_context, etc. It is provided in this form in + * order to avoid computing it every time the driver is initialised, and is + * suitable for direct consumption by the hardware. + */ +static const u8 prob_table_init[] = { + /* k_coeff_entropy_update_probs */ + /* block 0 */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xB0, 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0xF1, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF4, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF6, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFE, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 1 */ + 0xD9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE1, 0xFC, 0xF1, 0xFD, 0xFF, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFA, 0xF1, 0xFA, 0xFD, 0xFF, 0xFD, 0xFE, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xDF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEE, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 2 */ + 0xBA, 0xFB, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0xFB, 0xF4, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFB, 0xF3, 0xFD, 0xFE, 0xFF, 0xFE, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFB, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* block 3 */ + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFE, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xFE, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF6, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFE, 0xFB, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF8, 0xFE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF5, 0xFB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFD, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF9, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* kf_y_mode_probs */ + 0x91, 0x9C, 0xA3, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* split_mv_probs */ + 0x6E, 0x6F, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* bmode_prob */ + 0x78, 0x5A, 0x4F, 0x85, 0x57, 0x55, 0x50, 0x6F, + 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* sub_mv_ref_prob */ + 0x93, 0x88, 0x12, 0x00, + 0x6A, 0x91, 0x01, 0x00, + 0xB3, 0x79, 0x01, 0x00, + 0xDF, 0x01, 0x22, 0x00, + 0xD0, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* mv_counts_to_probs */ + 0x07, 0x01, 0x01, 0x8F, + 0x0E, 0x12, 0x0E, 0x6B, + 0x87, 0x40, 0x39, 0x44, + 0x3C, 0x38, 0x80, 0x41, + 0x9F, 0x86, 0x80, 0x22, + 0xEA, 0xBC, 0x80, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* kf_y_mode_tree */ + 0x84, 0x02, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + + /* y_mode_tree */ + 0x80, 0x02, 0x04, 0x06, 0x81, 0x82, 0x83, 0x84, + + /* uv_mode_tree */ + 0x80, 0x02, 0x81, 0x04, 0x82, 0x83, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, + + /* small_mv_tree */ + 0x02, 0x08, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* small_mv_tree again */ + 0x02, 0x08, 0x04, 0x06, 0x80, 0x81, 0x82, 0x83, + 0x0A, 0x0C, 0x84, 0x85, 0x86, 0x87, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* split_mv_tree */ + 0x83, 0x02, 0x82, 0x04, 0x80, 0x81, 0x00, 0x00, + + /* b_mode_tree */ + 0x80, 0x02, 0x81, 0x04, 0x82, 0x06, 0x08, 0x0C, + 0x83, 0x0A, 0x85, 0x86, 0x84, 0x0E, 0x87, 0x10, + 0x88, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* submv_ref_tree */ + 0x8A, 0x02, 0x8B, 0x04, 0x8C, 0x8D, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + /* mv_ref_tree */ + 0x87, 0x02, 0x85, 0x04, 0x86, 0x06, 0x88, 0x89, +}; + +/* + * This table is a copy of k_mv_entropy_update_probs from the VP8 + * specification. + * + * FIXME: If any other driver uses it, move this table to media/vp8-ctrls.h + */ +static const u8 k_mv_entropy_update_probs[2][V4L2_VP8_MV_PROB_CNT] = { + { 237, 246, 253, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 250, 250, 252, 254, 254 }, + { 231, 243, 245, 253, 254, 254, 254, 254, 254, + 254, 254, 254, 254, 254, 251, 251, 254, 254, 254 } +}; + +static uint8_t read_bits(struct cedrus_dev *dev, unsigned int bits_count, + unsigned int probability) +{ + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_VP8_GET_BITS | + VE_H264_TRIGGER_TYPE_BIN_LENS(bits_count) | + VE_H264_TRIGGER_TYPE_PROBABILITY(probability)); + + cedrus_wait_for(dev, VE_H264_STATUS, VE_H264_STATUS_VLD_BUSY); + + return cedrus_read(dev, VE_H264_BASIC_BITS); +} + +static void get_delta_q(struct cedrus_dev *dev) +{ + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 4, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } +} + +static void process_segmentation_info(struct cedrus_dev *dev) +{ + int update, i; + + update = read_bits(dev, 1, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 1, VP8_PROB_HALF); + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 7, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + } + + if (update) + for (i = 0; i < 3; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) + read_bits(dev, 8, VP8_PROB_HALF); +} + +static void process_ref_lf_delta_info(struct cedrus_dev *dev) +{ + if (read_bits(dev, 1, VP8_PROB_HALF)) { + int i; + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + for (i = 0; i < 4; i++) + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + } +} + +static void process_ref_frame_info(struct cedrus_dev *dev) +{ + u8 refresh_golden_frame = read_bits(dev, 1, VP8_PROB_HALF); + u8 refresh_alt_ref_frame = read_bits(dev, 1, VP8_PROB_HALF); + + if (!refresh_golden_frame) + read_bits(dev, 2, VP8_PROB_HALF); + + if (!refresh_alt_ref_frame) + read_bits(dev, 2, VP8_PROB_HALF); + + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); +} + +static void cedrus_irq_clear(struct cedrus_dev *dev) +{ + cedrus_write(dev, VE_H264_STATUS, + VE_H264_STATUS_INT_MASK); +} + +static void cedrus_read_header(struct cedrus_dev *dev, + const struct v4l2_ctrl_vp8_frame_header *slice) +{ + int i, j; + + if (VP8_FRAME_IS_KEY_FRAME(slice)) { + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 1, VP8_PROB_HALF); + } + + if (read_bits(dev, 1, VP8_PROB_HALF)) + process_segmentation_info(dev); + + read_bits(dev, 1, VP8_PROB_HALF); + read_bits(dev, 6, VP8_PROB_HALF); + read_bits(dev, 3, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) + process_ref_lf_delta_info(dev); + + read_bits(dev, 2, VP8_PROB_HALF); + + /* y_ac_qi */ + read_bits(dev, 7, VP8_PROB_HALF); + + /* Parses y_dc_delta, y2_dc_delta, etc. */ + for (i = 0; i < QUANT_DELTA_COUNT; i++) + get_delta_q(dev); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) + process_ref_frame_info(dev); + + read_bits(dev, 1, VP8_PROB_HALF); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) + read_bits(dev, 1, VP8_PROB_HALF); + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, VE_H264_TRIGGER_TYPE_VP8_UPDATE_COEF); + cedrus_wait_for(dev, VE_H264_STATUS, VE_H264_STATUS_VP8_UPPROB_BUSY); + cedrus_irq_clear(dev); + + if (read_bits(dev, 1, VP8_PROB_HALF)) + read_bits(dev, 8, VP8_PROB_HALF); + + if (!VP8_FRAME_IS_KEY_FRAME(slice)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + } + + if (read_bits(dev, 1, VP8_PROB_HALF)) { + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + read_bits(dev, 8, VP8_PROB_HALF); + } + + for (i = 0; i < 2; i++) + for (j = 0; j < V4L2_VP8_MV_PROB_CNT; j++) + if (read_bits(dev, 1, k_mv_entropy_update_probs[i][j])) + read_bits(dev, 7, VP8_PROB_HALF); + } +} + +static void cedrus_vp8_update_probs(const struct v4l2_ctrl_vp8_frame_header *slice, + u8 *prob_table) +{ + int i, j, k; + + memcpy(&prob_table[0x1008], slice->entropy_header.y_mode_probs, + sizeof(slice->entropy_header.y_mode_probs)); + memcpy(&prob_table[0x1010], slice->entropy_header.uv_mode_probs, + sizeof(slice->entropy_header.uv_mode_probs)); + + memcpy(&prob_table[0x1018], slice->segment_header.segment_probs, + sizeof(slice->segment_header.segment_probs)); + + prob_table[0x101c] = slice->prob_skip_false; + prob_table[0x101d] = slice->prob_intra; + prob_table[0x101e] = slice->prob_last; + prob_table[0x101f] = slice->prob_gf; + + memcpy(&prob_table[0x1020], slice->entropy_header.mv_probs[0], + V4L2_VP8_MV_PROB_CNT); + memcpy(&prob_table[0x1040], slice->entropy_header.mv_probs[1], + V4L2_VP8_MV_PROB_CNT); + + for (i = 0; i < 4; ++i) + for (j = 0; j < 8; ++j) + for (k = 0; k < 3; ++k) + memcpy(&prob_table[i * 512 + j * 64 + k * 16], + slice->entropy_header.coeff_probs[i][j][k], 11); +} + +static enum cedrus_irq_status +cedrus_vp8_irq_status(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_STATUS); + + if (reg & (VE_H264_STATUS_DECODE_ERR_INT | + VE_H264_STATUS_VLD_DATA_REQ_INT)) + return CEDRUS_IRQ_ERROR; + + if (reg & VE_H264_CTRL_SLICE_DECODE_INT) + return CEDRUS_IRQ_OK; + + return CEDRUS_IRQ_NONE; +} + +static void cedrus_vp8_irq_clear(struct cedrus_ctx *ctx) +{ + cedrus_irq_clear(ctx->dev); +} + +static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + u32 reg = cedrus_read(dev, VE_H264_CTRL); + + cedrus_write(dev, VE_H264_CTRL, + reg & ~VE_H264_CTRL_INT_MASK); +} + +static void cedrus_vp8_setup(struct cedrus_ctx *ctx, + struct cedrus_run *run) +{ + const struct v4l2_ctrl_vp8_frame_header *slice = run->vp8.frame_params; + struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q; + struct vb2_buffer *src_buf = &run->src->vb2_buf; + struct cedrus_dev *dev = ctx->dev; + dma_addr_t luma_addr, chroma_addr; + dma_addr_t src_buf_addr; + int header_size; + int qindex; + u32 reg; + + cedrus_engine_enable(ctx, CEDRUS_CODEC_VP8); + + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8); + + cedrus_vp8_update_probs(slice, ctx->codec.vp8.entropy_probs_buf); + + reg = slice->first_part_size * 8; + cedrus_write(dev, VE_VP8_FIRST_DATA_PART_LEN, reg); + + header_size = VP8_FRAME_IS_KEY_FRAME(slice) ? 10 : 3; + + reg = slice->first_part_size + header_size; + cedrus_write(dev, VE_VP8_PART_SIZE_OFFSET, reg); + + reg = vb2_plane_size(src_buf, 0) * 8; + cedrus_write(dev, VE_H264_VLD_LEN, reg); + + /* + * FIXME: There is a problem if frame header is skipped (adding + * first_part_header_bits to offset). It seems that functions + * for parsing bitstreams change internal state of VPU in some + * way that can't be otherwise set. Maybe this can be bypassed + * by somehow fixing probability table buffer? + */ + reg = header_size * 8; + cedrus_write(dev, VE_H264_VLD_OFFSET, reg); + + src_buf_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + cedrus_write(dev, VE_H264_VLD_END, + src_buf_addr + vb2_get_plane_payload(src_buf, 0)); + cedrus_write(dev, VE_H264_VLD_ADDR, + VE_H264_VLD_ADDR_VAL(src_buf_addr) | + VE_H264_VLD_ADDR_FIRST | VE_H264_VLD_ADDR_VALID | + VE_H264_VLD_ADDR_LAST); + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_INIT_SWDEC); + + cedrus_write(dev, VE_VP8_ENTROPY_PROBS_ADDR, + ctx->codec.vp8.entropy_probs_buf_dma); + + reg = 0; + switch (slice->version) { + case 1: + reg |= VE_VP8_PPS_FILTER_TYPE_SIMPLE; + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER; + break; + case 2: + reg |= VE_VP8_PPS_LPF_DISABLE; + reg |= VE_VP8_PPS_BILINEAR_MC_FILTER; + break; + case 3: + reg |= VE_VP8_PPS_LPF_DISABLE; + reg |= VE_VP8_PPS_FULL_PIXEL; + break; + } + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_UPDATE_MAP) + reg |= VE_VP8_PPS_UPDATE_MB_SEGMENTATION_MAP; + if (!(slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_DELTA_VALUE_MODE)) + reg |= VE_VP8_PPS_MB_SEGMENT_ABS_DELTA; + if (slice->segment_header.flags & V4L2_VP8_SEGMENT_HEADER_FLAG_ENABLED) + reg |= VE_VP8_PPS_SEGMENTATION_ENABLE; + if (ctx->codec.vp8.last_filter_type) + reg |= VE_VP8_PPS_LAST_LOOP_FILTER_SIMPLE; + reg |= VE_VP8_PPS_SHARPNESS_LEVEL(slice->lf_header.sharpness_level); + if (slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE) + reg |= VE_VP8_PPS_LOOP_FILTER_SIMPLE; + reg |= VE_VP8_PPS_LOOP_FILTER_LEVEL(slice->lf_header.level); + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_ADJ_ENABLE) + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_ENABLE; + if (slice->lf_header.flags & V4L2_VP8_LF_HEADER_DELTA_UPDATE) + reg |= VE_VP8_PPS_MODE_REF_LF_DELTA_UPDATE; + reg |= VE_VP8_PPS_TOKEN_PARTITION(ilog2(slice->num_dct_parts)); + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_MB_NO_SKIP_COEFF) + reg |= VE_VP8_PPS_MB_NO_COEFF_SKIP; + reg |= VE_VP8_PPS_RELOAD_ENTROPY_PROBS; + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_GOLDEN) + reg |= VE_VP8_PPS_GOLDEN_SIGN_BIAS; + if (slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_SIGN_BIAS_ALT) + reg |= VE_VP8_PPS_ALTREF_SIGN_BIAS; + if (ctx->codec.vp8.last_frame_p_type) + reg |= VE_VP8_PPS_LAST_PIC_TYPE_P_FRAME; + reg |= VE_VP8_PPS_LAST_SHARPNESS_LEVEL(ctx->codec.vp8.last_sharpness_level); + if (!(slice->flags & V4L2_VP8_FRAME_HEADER_FLAG_KEY_FRAME)) + reg |= VE_VP8_PPS_PIC_TYPE_P_FRAME; + cedrus_write(dev, VE_VP8_PPS, reg); + + cedrus_read_header(dev, slice); + + /* reset registers changed by HW */ + cedrus_write(dev, VE_H264_CUR_MB_NUM, 0); + cedrus_write(dev, VE_H264_MB_ADDR, 0); + cedrus_write(dev, VE_H264_ERROR_CASE, 0); + + reg = 0; + reg |= VE_VP8_QP_INDEX_DELTA_UVAC(slice->quant_header.uv_ac_delta); + reg |= VE_VP8_QP_INDEX_DELTA_UVDC(slice->quant_header.uv_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y2AC(slice->quant_header.y2_ac_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y2DC(slice->quant_header.y2_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_Y1DC(slice->quant_header.y_dc_delta); + reg |= VE_VP8_QP_INDEX_DELTA_BASE_QINDEX(slice->quant_header.y_ac_qi); + cedrus_write(dev, VE_VP8_QP_INDEX_DELTA, reg); + + reg = 0; + reg |= VE_VP8_FSIZE_WIDTH(slice->width); + reg |= VE_VP8_FSIZE_HEIGHT(slice->height); + cedrus_write(dev, VE_VP8_FSIZE, reg); + + reg = 0; + reg |= VE_VP8_PICSIZE_WIDTH(slice->width); + reg |= VE_VP8_PICSIZE_HEIGHT(slice->height); + cedrus_write(dev, VE_VP8_PICSIZE, reg); + + reg = 0; + reg |= VE_VP8_SEGMENT3(slice->segment_header.quant_update[3]); + reg |= VE_VP8_SEGMENT2(slice->segment_header.quant_update[2]); + reg |= VE_VP8_SEGMENT1(slice->segment_header.quant_update[1]); + reg |= VE_VP8_SEGMENT0(slice->segment_header.quant_update[0]); + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV0, reg); + + reg = 0; + reg |= VE_VP8_SEGMENT3(slice->segment_header.lf_update[3]); + reg |= VE_VP8_SEGMENT2(slice->segment_header.lf_update[2]); + reg |= VE_VP8_SEGMENT1(slice->segment_header.lf_update[1]); + reg |= VE_VP8_SEGMENT0(slice->segment_header.lf_update[0]); + cedrus_write(dev, VE_VP8_SEGMENT_FEAT_MB_LV1, reg); + + reg = 0; + reg |= VE_VP8_LF_DELTA3(slice->lf_header.ref_frm_delta[3]); + reg |= VE_VP8_LF_DELTA2(slice->lf_header.ref_frm_delta[2]); + reg |= VE_VP8_LF_DELTA1(slice->lf_header.ref_frm_delta[1]); + reg |= VE_VP8_LF_DELTA0(slice->lf_header.ref_frm_delta[0]); + cedrus_write(dev, VE_VP8_REF_LF_DELTA, reg); + + reg = 0; + reg |= VE_VP8_LF_DELTA3(slice->lf_header.mb_mode_delta[3]); + reg |= VE_VP8_LF_DELTA2(slice->lf_header.mb_mode_delta[2]); + reg |= VE_VP8_LF_DELTA1(slice->lf_header.mb_mode_delta[1]); + reg |= VE_VP8_LF_DELTA0(slice->lf_header.mb_mode_delta[0]); + cedrus_write(dev, VE_VP8_MODE_LF_DELTA, reg); + + luma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, run->dst->vb2_buf.index, 1); + cedrus_write(dev, VE_VP8_REC_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_REC_CHROMA, chroma_addr); + + qindex = vb2_find_timestamp(cap_q, slice->last_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_FWD_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_FWD_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_FWD_LUMA, 0); + cedrus_write(dev, VE_VP8_FWD_CHROMA, 0); + } + + qindex = vb2_find_timestamp(cap_q, slice->golden_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_BWD_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_BWD_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_BWD_LUMA, 0); + cedrus_write(dev, VE_VP8_BWD_CHROMA, 0); + } + + qindex = vb2_find_timestamp(cap_q, slice->alt_frame_ts, 0); + if (qindex >= 0) { + luma_addr = cedrus_dst_buf_addr(ctx, qindex, 0); + chroma_addr = cedrus_dst_buf_addr(ctx, qindex, 1); + cedrus_write(dev, VE_VP8_ALT_LUMA, luma_addr); + cedrus_write(dev, VE_VP8_ALT_CHROMA, chroma_addr); + } else { + cedrus_write(dev, VE_VP8_ALT_LUMA, 0); + cedrus_write(dev, VE_VP8_ALT_CHROMA, 0); + } + + cedrus_write(dev, VE_H264_CTRL, VE_H264_CTRL_VP8 | + VE_H264_CTRL_DECODE_ERR_INT | + VE_H264_CTRL_SLICE_DECODE_INT); + + if (slice->lf_header.level) { + ctx->codec.vp8.last_filter_type = + !!(slice->lf_header.flags & V4L2_VP8_LF_FILTER_TYPE_SIMPLE); + ctx->codec.vp8.last_frame_p_type = + !VP8_FRAME_IS_KEY_FRAME(slice); + ctx->codec.vp8.last_sharpness_level = + slice->lf_header.sharpness_level; + } +} + +static int cedrus_vp8_start(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + ctx->codec.vp8.entropy_probs_buf = + dma_alloc_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE, + &ctx->codec.vp8.entropy_probs_buf_dma, + GFP_KERNEL); + if (!ctx->codec.vp8.entropy_probs_buf) + return -ENOMEM; + + /* + * This offset has been discovered by reverse engineering, we don?t know + * what it actually means. + */ + memcpy(&ctx->codec.vp8.entropy_probs_buf[2048], + prob_table_init, sizeof(prob_table_init)); + + return 0; +} + +static void cedrus_vp8_stop(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_engine_disable(dev); + + dma_free_coherent(dev->dev, CEDRUS_ENTROPY_PROBS_SIZE, + ctx->codec.vp8.entropy_probs_buf, + ctx->codec.vp8.entropy_probs_buf_dma); +} + +static void cedrus_vp8_trigger(struct cedrus_ctx *ctx) +{ + struct cedrus_dev *dev = ctx->dev; + + cedrus_write(dev, VE_H264_TRIGGER_TYPE, + VE_H264_TRIGGER_TYPE_VP8_SLICE_DECODE); +} + +struct cedrus_dec_ops cedrus_dec_ops_vp8 = { + .irq_clear = cedrus_vp8_irq_clear, + .irq_disable = cedrus_vp8_irq_disable, + .irq_status = cedrus_vp8_irq_status, + .setup = cedrus_vp8_setup, + .start = cedrus_vp8_start, + .stop = cedrus_vp8_stop, + .trigger = cedrus_vp8_trigger, +}; -- 2.29.2 From ezequiel at vanguardiasur.com.ar Wed Nov 11 01:08:21 2020 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Tue, 10 Nov 2020 22:08:21 -0300 Subject: [RESEND PATCH 0/2] media: uapi: Expose VP8 probability lengths as defines In-Reply-To: <20201109162244.16531-1-linkmauve@linkmauve.fr> References: <20201109162244.16531-1-linkmauve@linkmauve.fr> Message-ID: Hi Emmanuel, Thanks for the patch. On Mon, 9 Nov 2020 at 15:37, Emmanuel Gil Peyrot wrote: > > These values will be used by various drivers implementing the VP8 > stateless API. > > This had been suggested by Ezequiel Garcia for the Cedrus VP8 driver. > > The only driver using this API (until now) has also been updated to use > these new defines. > > This is a resend because I forgot to include most maintainers, sorry for > that. It?s my very first patch to the kernel, I didn?t know about > scripts/get_maintainers.pl > I haven't validated these two patches, but on a first look, it seems it's a low-hanging fruit nice cleanup. Thanks for that! Since it seems you are looking for interesting things to contribute, note that the vp8-ctrls.h header is lacking some nice documentation on each structure. This should be done by looking at the VP8 syntax spec and documenting things appropriately. See how it's done for H.264 and VP9: https://patchwork.linuxtv.org/project/linux-media/patch/20200928201433.327068-1-ezequiel at collabora.com/ https://patchwork.kernel.org/project/linux-rockchip/patch/20201102190551.1223389-3-adrian.ratiu at collabora.com/ Thanks, Ezequiel > Emmanuel Gil Peyrot (2): > media: uapi: Expose probability lengths as defines > media: hantro: Use VP8 lengths defined in uapi > > drivers/staging/media/hantro/hantro_vp8.c | 4 ++-- > include/media/vp8-ctrls.h | 6 ++++-- > 2 files changed, 6 insertions(+), 4 deletions(-) > > -- > 2.29.2 > From dan.carpenter at oracle.com Wed Nov 11 09:28:32 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Wed, 11 Nov 2020 12:28:32 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201110202945.GF2375022@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> Message-ID: <20201111092832.GI29398@kadam> On Tue, Nov 10, 2020 at 09:29:45PM +0100, Thierry Reding wrote: > > + err = dev_pm_opp_of_add_table(dc->dev); > > + if (err) { > > + dev_err(dc->dev, "failed to add OPP table: %d\n", err); > > + goto put_hw; > > + } > > + > > + err = devm_add_action(dc->dev, tegra_dc_deinit_opp_table, dc); > > + if (err) > > + goto remove_table; > > Do these functions return positive values? If not, I'd prefer if this > check was more explicit (i.e. err < 0) for consistency with the rest of > this code. > Isn't it the other way around? It's only when the check is explicitly for "if (ret < 0)" that we have to wonder about positives. If the codes says "if (ret)" then we know that it doesn't return positive values and every non-zero is an error. In the kernel "if (ret)" is way more popular than "if (ret < 0)": $ git grep 'if (\(ret\|rc\|err\))' | wc -l 92927 $ git grep 'if (\(ret\|rc\|err\) < 0)' | wc -l 36577 And some of those are places where "ret" can be positive so we are forced to use the "if (ret < 0)" format. Checking for "if (ret)" is easier from a static analysis perspective. If it's one style is used consistently then they're the same but when there is a mismatch the "if (ret < 0) " will trigger a false positive and the "if (ret) " will not. int var; ret = frob(&var); if (ret < 0) return ret; Smatch thinks positive returns are not handled so it complains that "var can be uninitialized". regards, dan carpenter From ulf.hansson at linaro.org Wed Nov 11 11:38:23 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Wed, 11 Nov 2020 12:38:23 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> Message-ID: On Sun, 8 Nov 2020 at 13:19, Dmitry Osipenko wrote: > > 05.11.2020 18:22, Dmitry Osipenko ?????: > > 05.11.2020 12:45, Ulf Hansson ?????: > > ... > >> I need some more time to review this, but just a quick check found a > >> few potential issues... > > > > Thank you for starting the review! I'm pretty sure it will take a couple > > revisions until all the questions will be resolved :) > > > >> The "core-supply", that you specify as a regulator for each > >> controller's device node, is not the way we describe power domains. > >> Instead, it seems like you should register a power-domain provider > >> (with the help of genpd) and implement the ->set_performance_state() > >> callback for it. Each device node should then be hooked up to this > >> power-domain, rather than to a "core-supply". For DT bindings, please > >> have a look at Documentation/devicetree/bindings/power/power-domain.yaml > >> and Documentation/devicetree/bindings/power/power_domain.txt. > >> > >> In regards to the "sync state" problem (preventing to change > >> performance states until all consumers have been attached), this can > >> then be managed by the genpd provider driver instead. > > > > I'll need to take a closer look at GENPD, thank you for the suggestion. > > > > Sounds like a software GENPD driver which manages clocks and voltages > > could be a good idea, but it also could be an unnecessary > > over-engineering. Let's see.. > > > > Hello Ulf and all, > > I took a detailed look at the GENPD and tried to implement it. Here is > what was found: > > 1. GENPD framework doesn't aggregate performance requests from the > attached devices. This means that if deviceA requests performance state > 10 and then deviceB requests state 3, then framework will set domain's > state to 3 instead of 10. > > https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L376 As Viresh also stated, genpd does aggregate the votes. It even performs aggregation hierarchy (a genpd is allowed to have parent(s) to model a topology). > > 2. GENPD framework has a sync() callback in the genpd.domain structure, > but this callback isn't allowed to be used by the GENPD implementation. > The GENPD framework always overrides that callback for its own needs. > Hence GENPD doesn't allow to solve the bootstrapping > state-synchronization problem in a nice way. > > https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L2606 That ->sync() callback isn't the callback you are looking for, it's a PM domain specific callback - and has other purposes. To solve the problem you refer to, your genpd provider driver (a platform driver) should assign its ->sync_state() callback. The ->sync_state() callback will be invoked, when all consumer devices have been attached (and probed) to their corresponding provider. You may have a look at drivers/cpuidle/cpuidle-psci-domain.c, to see an example of how this works. If there is anything unclear, just tell me and I will try to help. > > 3. Tegra doesn't have a dedicated hardware power-controller for the core > domain, instead there is only an external voltage regulator. Hence we > will need to create a phony device-tree node for the virtual power > domain, which is probably a wrong thing to do. No, this is absolutely the correct thing to do. This isn't a virtual power domain, it's a real power domain. You only happen to model the control of it as a regulator, as it fits nicely with that for *this* SoC. Don't get me wrong, that's fine as long as the supply is specified only in the power-domain provider node. On another SoC, you might have a different FW interface for the power domain provider that doesn't fit well with the regulator. When that happens, all you need to do is to implement a new power domain provider and potentially re-define the power domain topology. More importantly, you don't need to re-invent yet another slew of device specific bindings - for each SoC. > > === > > Perhaps it should be possible to create some hacks to work around > bullets 2 and 3 in order to achieve what we need for DVFS on Tegra, but > bullet 1 isn't solvable without changing how the GENPD core works. > > Altogether, the GENPD in its current form is a wrong abstraction for a > system-wide DVFS in a case where multiple devices share power domain and > this domain is a voltage regulator. The regulator framework is the > correct abstraction in this case for today. Well, I admit it's a bit complex. But it solves the problem in a nicely abstracted way that should work for everybody, at least in my opinion. Although, let's not exclude that there are pieces missing in genpd or the opp layer, as this DVFS feature is rather new - but then we should just extend/fix it. Kind regards Uffe From ulf.hansson at linaro.org Wed Nov 11 11:45:02 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Wed, 11 Nov 2020 12:45:02 +0100 Subject: [PATCH v1 01/30] dt-bindings: host1x: Document OPP and voltage regulator properties In-Reply-To: <20201104234427.26477-2-digetx@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-2-digetx@gmail.com> Message-ID: On Thu, 5 Nov 2020 at 00:44, Dmitry Osipenko wrote: > > Document new DVFS OPP table and voltage regulator properties of the > Host1x bus and devices sitting on the bus. > > Signed-off-by: Dmitry Osipenko > --- > .../display/tegra/nvidia,tegra20-host1x.txt | 56 +++++++++++++++++++ > 1 file changed, 56 insertions(+) > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt > index 34d993338453..0593c8df70bb 100644 > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt > @@ -20,6 +20,18 @@ Required properties: > - reset-names: Must include the following entries: > - host1x > > +Optional properties: > +- operating-points-v2: See ../bindings/opp/opp.txt for details. > +- core-supply: Phandle of voltage regulator of the SoC "core" power domain. > + > +For each opp entry in 'operating-points-v2' table of host1x and its modules: > +- opp-supported-hw: One bitfield indicating: > + On Tegra20: SoC process ID mask > + On Tegra30+: SoC speedo ID mask > + > + A bitwise AND is performed against the value and if any bit > + matches, the OPP gets enabled. > + > Each host1x client module having to perform DMA through the Memory Controller > should have the interconnect endpoints set to the Memory Client and External > Memory respectively. > @@ -45,6 +57,8 @@ of the following host1x client modules: > - interconnect-names: Must include name of the interconnect path for each > interconnect entry. Consult TRM documentation for information about > available memory clients, see MEMORY CONTROLLER section. > + - core-supply: Phandle of voltage regulator of the SoC "core" power domain. > + - operating-points-v2: See ../bindings/opp/opp.txt for details. > As discussed in the thread for the cover-letter. We already have DT bindings for power-domains (providers and consumers). Please use them instead of adding SoC specific bindings to each peripheral device. [...] Kind regards Uffe From broonie at kernel.org Wed Nov 11 11:55:34 2020 From: broonie at kernel.org (Mark Brown) Date: Wed, 11 Nov 2020 11:55:34 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> Message-ID: <20201111115534.GA4847@sirena.org.uk> On Wed, Nov 11, 2020 at 12:23:41AM +0300, Dmitry Osipenko wrote: > 10.11.2020 23:32, Mark Brown ?????: > >>> + if (!device_property_present(dc->dev, "core-supply")) > >>> + return; > >> This is a potentially heavy operation, so I think we should avoid that > >> here. How about you use devm_regulator_get_optional() in ->probe()? That > >> returns -ENODEV if no regulator was specified, in which case you can set > >> dc->core_reg = NULL and use that as the condition here. > > Or enumerate the configurable voltages after getting the regulator and > > handle that appropriately which would be more robust in case there's > > missing or unusual constraints. > I already changed that code to use regulator_get_optional() for v2. That doesn't look entirely appropriate given that the core does most likely require some kind of power to operate. > Regarding the enumerating supported voltage.. I think this should be > done by the OPP core, but regulator core doesn't work well if > regulator_get() is invoked more than one time for the same device, at > least there is a loud debugfs warning about an already existing I don't understand why this would be an issue - if nothing else the core could just offer an interface to trigger the check. > directory for a regulator. It's easy to check whether the debug > directory exists before creating it, like thermal framework does it for > example, but then there were some other more difficult issues.. I don't > recall what they were right now. Perhaps will be easier to simply get a > error from regulator_set_voltage() for now because it shouldn't ever > happen in practice, unless device-tree has wrong constraints. The constraints might not be wrong, there might be some board which has a constraint somewhere for -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From www.cloudwaysapps.com at kshamadevigroup.com Wed Nov 11 12:02:56 2020 From: www.cloudwaysapps.com at kshamadevigroup.com (Ministry Of Agriculture) Date: Wed, 11 Nov 2020 04:02:56 -0800 Subject: Purchase|Outsorucing-Department| Message-ID: <20201111122007.0462D8753F@hemlock.osuosl.org> Good morning, I am writing again to inform you that I am yet to receives your email correspondent concerning the previous email I sent to you. Please let me know if you will be able to sale the product's to my director directly. Could you kindly reply, is urgent for business. Regards, Ghana Agricultural Project Commission Purchase|Outsorucing-Department| GGBGZFHNEZBYLRYIDDZYDUPIFDXNRYSCPDGFBE From www.cloudwaysapps.com at kshamadevigroup.com Wed Nov 11 12:02:56 2020 From: www.cloudwaysapps.com at kshamadevigroup.com (Ministry Of Agriculture) Date: Wed, 11 Nov 2020 04:02:56 -0800 Subject: Purchase|Outsorucing-Department| Message-ID: <20201111122007.15A052DDC9@silver.osuosl.org> Good morning, I am writing again to inform you that I am yet to receives your email correspondent concerning the previous email I sent to you. Please let me know if you will be able to sale the product's to my director directly. Could you kindly reply, is urgent for business. Regards, Ghana Agricultural Project Commission Purchase|Outsorucing-Department| GGBGZFHNEZBYLRYIDDZYDUPIFDXNRYSCPDGFBE From hverkuil-cisco at xs4all.nl Wed Nov 11 14:42:59 2020 From: hverkuil-cisco at xs4all.nl (Hans Verkuil) Date: Wed, 11 Nov 2020 15:42:59 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201106151411.321743-1-maxime@cerno.tech> References: <20201106151411.321743-1-maxime@cerno.tech> Message-ID: <33ed44c6-e54d-3769-2a59-ab6c50b49053@xs4all.nl> On 06/11/2020 16:14, Maxime Ripard wrote: > Hi, > > Here's an attempt to removing the dma_direct_set_offset calls we have in > numerous drivers and move all those quirks into a global notifier as suggested > by Robin. For patches 4-7: Acked-by: Hans Verkuil It's fine by me if this series is merged via the drm subsystem. Regards, Hans > > Let me know what you think, > Maxime > > Maxime Ripard (7): > drm/sun4i: backend: Fix probe failure with multiple backends > soc: sunxi: Deal with the MBUS DMA offsets in a central place > drm/sun4i: backend: Remove the MBUS quirks > media: sun4i: Remove the MBUS quirks > media: sun6i: Remove the MBUS quirks > media: cedrus: Remove the MBUS quirks > media: sun8i-di: Remove the call to of_dma_configure > > drivers/gpu/drm/sun4i/sun4i_backend.c | 13 -- > .../platform/sunxi/sun4i-csi/sun4i_csi.c | 27 ---- > .../platform/sunxi/sun6i-csi/sun6i_csi.c | 17 --- > .../media/platform/sunxi/sun8i-di/sun8i-di.c | 4 - > drivers/soc/sunxi/Kconfig | 8 ++ > drivers/soc/sunxi/Makefile | 1 + > drivers/soc/sunxi/sunxi_mbus.c | 132 ++++++++++++++++++ > drivers/staging/media/sunxi/cedrus/cedrus.c | 1 - > drivers/staging/media/sunxi/cedrus/cedrus.h | 3 - > .../staging/media/sunxi/cedrus/cedrus_hw.c | 18 --- > 10 files changed, 141 insertions(+), 83 deletions(-) > create mode 100644 drivers/soc/sunxi/sunxi_mbus.c > From sergio.paracuellos at gmail.com Wed Nov 11 16:30:06 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:06 +0100 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 Message-ID: <20201111163013.29412-1-sergio.paracuellos@gmail.com> This patchset ports CPU clock detection for MT7621 from OpenWrt and adds a complete clock plan for the mt7621 SOC. The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS (AHB?). * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. No documentation about a probably existant set of dividers for each ip core is included in the datasheets. So we cannot make anything better, AFAICT. Looking into driver code, there is another frequency which is used in some drivers (uart, sd...) which for any reason is always hardcoded to 50 MHz. Taking this into account this patchset provides three main fixed clocks to the SOC in 'mt7621-pll' which are: - "cpu": with detected frequency (900 MHz in my board). - "ahb": cpu / 4 = 225 Mhz. - "apb": 50 Mhz. PLL controller cannot be manipulatedbecause there is no info about how to do it. Because of this, there is nothing related with registers in the included binding. It also provides a clock gate driver 'mt7621-clk' as a platform driver to allow to enable and disable some clocks in the different ip cores. The parent clocks for this clock gates have also set taking into account existant device tree and driver code resulting in the followings: - "hsdma": "ahb" - "fe": "ahb" - "sp_divtx": "ahb" - "timer": "cpu" - "int": "cpu" - "mc": "ahb" - "pcm": "ahb" - "pio": "ahb" - "gdma": "ahb" - "nand": "ahb" - "i2c": "ahb" - "i2s": "ahb" - "spi": "ahb" - "uart1": "apb" - "uart2": "apb" - "uart3": "apb" - "eth": "ahb" - "pcie0": "ahb" - "pcie1": "ahb" - "pcie2": "ahb" - "crypto": "ahb" - "shxc": "ahb" There was a previous attempt of doing this here[0] but the author did not wanted to make assumptions of a clock plan for the platform. I do really want this to be upstreamed so according to the comments in previous attempt[0] from Oleksij Rempel I have tried to do this by myself. All of this patches have been tested in a GNUBee PC1 resulting in a working platform. [0]: https://www.lkml.org/lkml/2019/7/23/1044 Sergio Paracuellos (7): dt-bindings: clock: add dt binding header for mt7621 clocks dt: bindings: add mt7621-pll device tree binding documentation dt: bindings: add mt7621-clk device tree binding documentation MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621 clk: ralink: add clock gate driver for mt7621 SoC staging: mt7621-dts: make use of new 'mt7621-pll' and 'mt7621-clk' MAINTAINERS: add MT7621 CLOCK maintainer .../bindings/clock/mediatek,mt7621-clk.yaml | 52 ++++ .../bindings/clock/mediatek,mt7621-pll.yaml | 51 ++++ MAINTAINERS | 8 + arch/mips/include/asm/mach-ralink/mt7621.h | 20 ++ arch/mips/ralink/mt7621.c | 87 ++++++ drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 + drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 258 ++++++++++++++++++ drivers/staging/mt7621-dts/gbpc1.dts | 11 - drivers/staging/mt7621-dts/mt7621.dtsi | 71 +++-- include/dt-bindings/clock/mt7621-clk.h | 39 +++ 13 files changed, 567 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:07 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:07 +0100 Subject: [PATCH 1/7] dt-bindings: clock: add dt binding header for mt7621 clocks In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-2-sergio.paracuellos@gmail.com> Adds dt binding header for 'mediatek,mt7621-pll' PLL controller and for 'mediatek,mt7621-clk' clock gates. Signed-off-by: Sergio Paracuellos --- include/dt-bindings/clock/mt7621-clk.h | 39 ++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 include/dt-bindings/clock/mt7621-clk.h diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 000000000000..8fccfa514185 --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Author: Sergio Paracuellos + */ + +#ifndef _DT_BINDINGS_CLK_MT7621_H +#define _DT_BINDINGS_CLK_MT7621_H + +/* SYS CLOCKS */ +#define MT7621_CLK_CPU 0 +#define MT7621_CLK_AHB 1 +#define MT7621_CLK_APB 2 +#define MT7621_CLK_MAX 3 + +/* CLOCK GATES */ +#define MT7621_CLK_HSDMA 0 +#define MT7621_CLK_FE 1 +#define MT7621_CLK_SP_DIVTX 2 +#define MT7621_CLK_TIMER 3 +#define MT7621_CLK_INT 4 +#define MT7621_CLK_MC 5 +#define MT7621_CLK_PCM 6 +#define MT7621_CLK_PIO 7 +#define MT7621_CLK_GDMA 8 +#define MT7621_CLK_NAND 9 +#define MT7621_CLK_I2C 10 +#define MT7621_CLK_I2S 11 +#define MT7621_CLK_SPI 12 +#define MT7621_CLK_UART1 13 +#define MT7621_CLK_UART2 14 +#define MT7621_CLK_UART3 15 +#define MT7621_CLK_ETH 16 +#define MT7621_CLK_PCIE0 17 +#define MT7621_CLK_PCIE1 18 +#define MT7621_CLK_PCIE2 19 +#define MT7621_CLK_CRYPTO 20 +#define MT7621_CLK_SHXC 21 + +#endif /* _DT_BINDINGS_CLK_MT7621_H */ -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:08 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:08 +0100 Subject: [PATCH 2/7] dt: bindings: add mt7621-pll device tree binding documentation In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-3-sergio.paracuellos@gmail.com> Adds device tree binding documentation for PLL controller in the MT7621 SOC. Signed-off-by: Sergio Paracuellos --- .../bindings/clock/mediatek,mt7621-pll.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml new file mode 100644 index 000000000000..ef58411065e4 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-pll.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT7621 PLL Controller Device Tree Bindings + +maintainers: + - Sergio Paracuellos + + +description: | + The PLL Controller provides the cpu clock as well as derived + clock for the bus and the peripherals. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in: + [1]: . + +properties: + compatible: + const: mediatek,mt7621-pll + + "#clock-cells": + description: + The first cell indicates the clock number, see [1] for available + clocks. + const: 1 + + clock-output-names: + maxItems: 3 + +required: + - compatible + - '#clock-cells' + - clock-output-names + +additionalProperties: false + +examples: + - | + #include + + pll { + compatible = "mediatek,mt7621-pll"; + #clock-cells = <1>; + clock-output-names = "cpu", "ahb", "apb"; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:09 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:09 +0100 Subject: [PATCH 3/7] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-4-sergio.paracuellos@gmail.com> Adds device tree binding documentation for clock gates in the MT7621 SOC. Signed-off-by: Sergio Paracuellos --- .../bindings/clock/mediatek,mt7621-clk.yaml | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml new file mode 100644 index 000000000000..89886b066849 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml @@ -0,0 +1,52 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT7621 Bus Gates Clock Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +description: | + The MT7621 can gate SoC device clocks. + + Each clock gate is assigned an identifier and client nodes use this identifier + to specify the clock gate which they consume. + + All these identifiers could be found in: + [1]: . + +properties: + compatible: + const: mediatek,mt7621-clk + + "#clock-cells": + description: + The first cell indicates the clock gate number, see [1] for available + clocks. + const: 1 + + ralink,sysctl: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the syscon which is in the same address area with syscon + device. + +required: + - compatible + - '#clock-cells' + - ralink,sysctl + +additionalProperties: false + +examples: + - | + #include + + clkctrl { + compatible = "mediatek,mt7621-clk"; + #clock-cells = <1>; + ralink,sysctl = <&sysc>; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:10 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:10 +0100 Subject: [PATCH 4/7] MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621 In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-5-sergio.paracuellos@gmail.com> For a long time the mt7621 uses a fixed cpu clock which causes a problem if the cpu frequency is not 880MHz. This patch adds cpu/ahb/apb clock calculation code and binds clocks to mt7621-pll node. Adapted from OpenWrt: c7ca224299 ramips: fix cpu clock of mt7621 and add dt clk devices Signed-off-by: Weijie Gao Signed-off-by: Chuanhong Guo Signed-off-by: Sergio Paracuellos --- arch/mips/include/asm/mach-ralink/mt7621.h | 20 +++++ arch/mips/ralink/mt7621.c | 87 ++++++++++++++++++++++ 2 files changed, 107 insertions(+) diff --git a/arch/mips/include/asm/mach-ralink/mt7621.h b/arch/mips/include/asm/mach-ralink/mt7621.h index e1af1ba50bd8..a9f3febddf1c 100644 --- a/arch/mips/include/asm/mach-ralink/mt7621.h +++ b/arch/mips/include/asm/mach-ralink/mt7621.h @@ -17,6 +17,10 @@ #define SYSC_REG_CHIP_REV 0x0c #define SYSC_REG_SYSTEM_CONFIG0 0x10 #define SYSC_REG_SYSTEM_CONFIG1 0x14 +#define SYSC_REG_CLKCFG0 0x2c +#define SYSC_REG_CUR_CLK_STS 0x44 + +#define MEMC_REG_CPU_PLL 0x648 #define CHIP_REV_PKG_MASK 0x1 #define CHIP_REV_PKG_SHIFT 16 @@ -24,6 +28,22 @@ #define CHIP_REV_VER_SHIFT 8 #define CHIP_REV_ECO_MASK 0xf +#define XTAL_MODE_SEL_MASK 0x7 +#define XTAL_MODE_SEL_SHIFT 6 + +#define CPU_CLK_SEL_MASK 0x3 +#define CPU_CLK_SEL_SHIFT 30 + +#define CUR_CPU_FDIV_MASK 0x1f +#define CUR_CPU_FDIV_SHIFT 8 +#define CUR_CPU_FFRAC_MASK 0x1f +#define CUR_CPU_FFRAC_SHIFT 0 + +#define CPU_PLL_PREDIV_MASK 0x3 +#define CPU_PLL_PREDIV_SHIFT 12 +#define CPU_PLL_FBDIV_MASK 0x7f +#define CPU_PLL_FBDIV_SHIFT 4 + #define MT7621_DRAM_BASE 0x0 #define MT7621_DDR2_SIZE_MIN 32 #define MT7621_DDR2_SIZE_MAX 256 diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index ca0ac607b0f3..4fce37e5ea7a 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -9,12 +9,17 @@ #include #include #include +#include +#include +#include +#include #include #include #include #include #include +#include #include @@ -105,11 +110,93 @@ static struct rt2880_pmx_group mt7621_pinmux_data[] = { { 0 } }; +static struct clk *clks[MT7621_CLK_MAX]; +static struct clk_onecell_data clk_data = { + .clks = clks, + .clk_num = ARRAY_SIZE(clks), +}; + phys_addr_t mips_cpc_default_phys_base(void) { panic("Cannot detect cpc address"); } +static struct clk *__init mt7621_add_sys_clkdev( + const char *id, const char *parent_id, unsigned long rate) +{ + struct clk *clk; + int err; + + clk = clk_register_fixed_rate(NULL, id, parent_id, 0, rate); + if (IS_ERR(clk)) + panic("failed to allocate %s clock structure", id); + + err = clk_register_clkdev(clk, id, NULL); + if (err) + panic("unable to register %s clock device", id); + + return clk; +} + +#define MHZ(x) ((x) * 1000 * 1000) + +void __init ralink_clk_init(void) +{ + u32 syscfg, xtal_sel, clkcfg, clk_sel, curclk, ffiv, ffrac; + u32 pll, prediv, fbdiv; + u32 xtal_clk, cpu_clk, ahb_clk, apb_clk; + static const u32 prediv_tbl[] = { 0, 1, 2, 2 }; + + syscfg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0); + xtal_sel = (syscfg >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; + + clkcfg = rt_sysc_r32(SYSC_REG_CLKCFG0); + clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK; + + curclk = rt_sysc_r32(SYSC_REG_CUR_CLK_STS); + ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK; + ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK; + + if (xtal_sel <= 2) + xtal_clk = MHZ(20); + else if (xtal_sel <= 5) + xtal_clk = MHZ(40); + else + xtal_clk = MHZ(25); + + switch (clk_sel) { + case 0: + cpu_clk = MHZ(500); + break; + case 1: + pll = rt_memc_r32(MEMC_REG_CPU_PLL); + fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK; + prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK; + cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; + break; + default: + cpu_clk = xtal_clk; + } + + cpu_clk = cpu_clk / ffiv * ffrac; + ahb_clk = cpu_clk / 4; + apb_clk = MHZ(50); + + clks[MT7621_CLK_CPU] = mt7621_add_sys_clkdev("cpu", NULL, cpu_clk); + clks[MT7621_CLK_AHB] = mt7621_add_sys_clkdev("ahb", NULL, ahb_clk); + clks[MT7621_CLK_APB] = mt7621_add_sys_clkdev("apb", NULL, apb_clk); + + pr_info("CPU Clock: %dMHz\n", cpu_clk / 1000000); + mips_hpt_frequency = cpu_clk / 2; +} + +static void __init mt7621_clocks_init_dt(struct device_node *np) +{ + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); +} + +CLK_OF_DECLARE(ar7100, "mediatek,mt7621-pll", mt7621_clocks_init_dt); + void __init ralink_of_remap(void) { rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc"); -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:11 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:11 +0100 Subject: [PATCH 5/7] clk: ralink: add clock gate driver for mt7621 SoC In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-6-sergio.paracuellos@gmail.com> In mt7621 SoC register 'SYSC_REG_CPLL_CLKCFG1' allows to handle a bunch of gates to enable/disable clocks for all or some ip cores. Add a driver to properly handle them. Parent clocks for this gates are not documented at all in the SoC documentation so all of them have been assumed looking into the clock frequencies used in its related driver code. There are three main clocks which are "cpu", "ahb" and "apb" from the 'mt7621-pll'. The following parents are set to each GATE: * "hsdma": "ahb" * "fe": "ahb" * "sp_divtx": "ahb" * "timer": "cpu" * "int": "cpu" * "mc": "ahb" * "pcm": "ahb" * "pio": "ahb" * "gdma": "ahb" * "nand": "ahb" * "i2c": "ahb" * "i2s": "ahb" * "spi": "ahb" * "uart1": "apb" * "uart2": "apb" * "uart3": "apb" * "eth": "ahb" * "pcie0": "ahb" * "pcie1": "ahb" * "pcie2": "ahb" * "crypto": "ahb" * "shxc": "ahb" With this information the clk driver will provide gate functionality from a a set of hardcoded clocks allowing to define a nice device tree without fixed clocks. Signed-off-by: Sergio Paracuellos --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 ++ drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 258 ++++++++++++++++++++++++++++++++ 5 files changed, 276 insertions(+) create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..5f94c4329033 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -372,6 +372,7 @@ source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" +source "drivers/clk/ralink/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..6578e167b047 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-y += ralink/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ diff --git a/drivers/clk/ralink/Kconfig b/drivers/clk/ralink/Kconfig new file mode 100644 index 000000000000..7e8697327e0c --- /dev/null +++ b/drivers/clk/ralink/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# MediaTek Mt7621 Clock Driver +# +menu "Clock driver for mediatek mt7621 SoC" + depends on SOC_MT7621 || COMPILE_TEST + +config CLK_MT7621 + bool "Clock driver for MediaTek MT7621" + depends on SOC_MT7621 || COMPILE_TEST + default SOC_MT7621 + help + This driver supports MediaTek MT7621 basic clocks. +endmenu diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile new file mode 100644 index 000000000000..cf6f9216379d --- /dev/null +++ b/drivers/clk/ralink/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_MT7621) += clk-mt7621.o diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c new file mode 100644 index 000000000000..f7279d784a36 --- /dev/null +++ b/drivers/clk/ralink/clk-mt7621.c @@ -0,0 +1,258 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mediatek MT7621 Clock gate Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include + +/* clock gate configuration register */ +#define SYSC_REG_CLKCFG1 0x30 + +/* Gate register enable bits */ +#define MT7621_HSDMA_CLK_EN BIT(5) +#define MT7621_FE_CLK_EN BIT(6) +#define MT7621_SP_DIVTX_CLK_EN BIT(7) +#define MT7621_TIMER_CLK_EN BIT(8) +#define MT7621_INT_CLK_EN BIT(9) +#define MT7621_MC_CLK_EN BIT(10) +#define MT7621_PCM_CLK_EN BIT(11) +#define MT7621_PIO_CLK_EN BIT(13) +#define MT7621_GDMA_CLK_EN BIT(14) +#define MT7621_NAND_CLK_EN BIT(15) +#define MT7621_I2C_CLK_EN BIT(16) +#define MT7621_I2S_CLK_EN BIT(17) +#define MT7621_SPI_CLK_EN BIT(18) +#define MT7621_UART1_CLK_EN BIT(19) +#define MT7621_UART2_CLK_EN BIT(20) +#define MT7621_UART3_CLK_EN BIT(21) +#define MT7621_ETH_CLK_EN BIT(23) +#define MT7621_PCIE0_CLK_EN BIT(24) +#define MT7621_PCIE1_CLK_EN BIT(25) +#define MT7621_PCIE2_CLK_EN BIT(26) +#define MT7621_CRYPTO_CLK_EN BIT(29) +#define MT7621_SHXC_CLK_EN BIT(30) + +struct mt7621_clk_provider { + struct device_node *node; + struct device *dev; + struct regmap *syscon_regmap; + struct clk_hw_onecell_data *clk_data; +}; + +struct mt7621_gate { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + struct clk_hw hw; + u32 bit_idx; +}; + +struct mt7621_gate_data { + u8 idx; + const char *name; + const char *parent_name; + u32 bit_idx; +}; + +#define GATE(_id, _name, _pname, _shift) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .bit_idx = _shift \ + } + +static const struct mt7621_gate mt7621_gates[] = { + GATE(MT7621_CLK_HSDMA, "hsdma", "ahb", MT7621_HSDMA_CLK_EN), + GATE(MT7621_CLK_FE, "fe", "ahb", MT7621_FE_CLK_EN), + GATE(MT7621_CLK_SP_DIVTX, "sp_divtx", "ahb", MT7621_SP_DIVTX_CLK_EN), + GATE(MT7621_CLK_TIMER, "timer", "cpu", MT7621_TIMER_CLK_EN), + GATE(MT7621_CLK_INT, "int", "cpu", MT7621_INT_CLK_EN), + GATE(MT7621_CLK_MC, "mc", "ahb", MT7621_MC_CLK_EN), + GATE(MT7621_CLK_PCM, "pcm", "ahb", MT7621_PCM_CLK_EN), + GATE(MT7621_CLK_PIO, "pio", "ahb", MT7621_PIO_CLK_EN), + GATE(MT7621_CLK_GDMA, "gdma", "ahb", MT7621_GDMA_CLK_EN), + GATE(MT7621_CLK_NAND, "nand", "ahb", MT7621_NAND_CLK_EN), + GATE(MT7621_CLK_I2C, "i2c", "ahb", MT7621_I2C_CLK_EN), + GATE(MT7621_CLK_I2S, "i2s", "ahb", MT7621_I2S_CLK_EN), + GATE(MT7621_CLK_SPI, "spi", "ahb", MT7621_SPI_CLK_EN), + GATE(MT7621_CLK_UART1, "uart1", "apb", MT7621_UART1_CLK_EN), + GATE(MT7621_CLK_UART2, "uart2", "apb", MT7621_UART2_CLK_EN), + GATE(MT7621_CLK_UART3, "uart3", "apb", MT7621_UART3_CLK_EN), + GATE(MT7621_CLK_ETH, "eth", "ahb", MT7621_ETH_CLK_EN), + GATE(MT7621_CLK_PCIE0, "pcie0", "ahb", MT7621_PCIE0_CLK_EN), + GATE(MT7621_CLK_PCIE1, "pcie1", "ahb", MT7621_PCIE1_CLK_EN), + GATE(MT7621_CLK_PCIE2, "pcie2", "ahb", MT7621_PCIE2_CLK_EN), + GATE(MT7621_CLK_CRYPTO, "crypto", "ahb", MT7621_CRYPTO_CLK_EN), + GATE(MT7621_CLK_SHXC, "shxc", "ahb", MT7621_SHXC_CLK_EN) +}; + +static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_gate, hw); +} + +static int mt7621_gate_enable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + return regmap_update_bits(scon, SYSC_REG_CLKCFG1, + clk_gate->bit_idx, clk_gate->bit_idx); +} + +static void mt7621_gate_disable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + regmap_update_bits(scon, SYSC_REG_CLKCFG1, clk_gate->bit_idx, 0); +} + +static int mt7621_gate_is_enabled(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + unsigned int val; + + if (regmap_read(scon, SYSC_REG_CLKCFG1, &val)) + return 0; + + return val & clk_gate->bit_idx; +} + +static const struct clk_ops mt7621_gate_ops = { + .enable = mt7621_gate_enable, + .disable = mt7621_gate_disable, + .is_enabled = mt7621_gate_is_enabled, +}; + +static int mt7621_gate_ops_init(struct device *dev, struct mt7621_gate *sclk) +{ + struct clk_init_data init = { + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .num_parents = 1, + .parent_names = &sclk->parent_name, + .ops = &mt7621_gate_ops, + .name = sclk->name, + }; + + sclk->hw.init = &init; + return devm_clk_hw_register(dev, &sclk->hw); +} + +static int mt7621_register_gates(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct device *dev = clk_prov->dev; + int idx, err, count; + struct clk_hw **hws; + + count = ARRAY_SIZE(mt7621_gates); + *clk_data = devm_kzalloc(dev, struct_size(*clk_data, hws, count), + GFP_KERNEL); + if (!*clk_data) + return -ENOMEM; + + (*clk_data)->num = count; + hws = (*clk_data)->hws; + + for (idx = 0; idx < ARRAY_SIZE(mt7621_gates); idx++) { + struct mt7621_gate *sclk; + + sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL); + if (!sclk) + return -ENOMEM; + + sclk->idx = mt7621_gates[idx].idx; + sclk->name = mt7621_gates[idx].name; + sclk->parent_name = mt7621_gates[idx].parent_name; + sclk->bit_idx = mt7621_gates[idx].bit_idx; + sclk->clk_prov = clk_prov; + + err = mt7621_gate_ops_init(dev, sclk); + if (err) { + dev_err(dev, "failed to register clock %d\n", idx); + devm_kfree(dev, sclk); + hws[idx] = NULL; + } else { + dev_info(dev, "Registered clock gate: %s\n", + mt7621_gates[idx].name); + hws[idx] = &sclk->hw; + } + } + + return 0; +} + +static int mt7621_clk_init(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = pdev->dev.of_node; + struct mt7621_clk_provider *clk_provider; + int ret; + + clk_provider = devm_kzalloc(dev, sizeof(*clk_provider), GFP_KERNEL); + if (!clk_provider) + return -ENOMEM; + + platform_set_drvdata(pdev, clk_provider); + clk_provider->syscon_regmap = syscon_regmap_lookup_by_phandle(node, "ralink,sysctl"); + if (IS_ERR(clk_provider->syscon_regmap)) { + dev_err(dev, "Could not get syscon regmap\n"); + return -EINVAL; + } + + clk_provider->node = node; + clk_provider->dev = dev; + + ret = mt7621_register_gates(clk_provider); + if (ret) { + dev_err(dev, "Error registering gates\n"); + return ret; + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + clk_provider->clk_data); +} + +static int clk_mt7621_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + int ret; + + ret = mt7621_clk_init(pdev); + if (ret) { + dev_err(dev, "Could not register clock provider: %s: %d\n", + pdev->name, ret); + return ret; + } + + return 0; +} + +static const struct of_device_id of_match_clk_mt7621[] = { + { .compatible = "mediatek,mt7621-clk", .data = mt7621_clk_init }, + {} +}; + +static struct platform_driver clk_mt7621_drv = { + .probe = clk_mt7621_probe, + .driver = { + .name = "clk-mt7621", + .of_match_table = of_match_clk_mt7621, + }, +}; +builtin_platform_driver(clk_mt7621_drv); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("Mediatek Mt7621 clock gate driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:13 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:13 +0100 Subject: [PATCH 7/7] MAINTAINERS: add MT7621 CLOCK maintainer In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-8-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 clock driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f1f088a29bc2..c34c12d62355 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11142,6 +11142,14 @@ L: linux-wireless at vger.kernel.org S: Maintained F: drivers/net/wireless/mediatek/mt7601u/ +MEDIATEK MT7621 CLOCK DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml +F: Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml +F: arch/mips/ralink/mt7621.c +F: drivers/clk/ralink/clk-mt7621.c + MEDIATEK MT7621/28/88 I2C DRIVER M: Stefan Roese L: linux-i2c at vger.kernel.org -- 2.25.1 From sergio.paracuellos at gmail.com Wed Nov 11 16:30:12 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Wed, 11 Nov 2020 17:30:12 +0100 Subject: [PATCH 6/7] staging: mt7621-dts: make use of new 'mt7621-pll' and 'mt7621-clk' In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: <20201111163013.29412-7-sergio.paracuellos@gmail.com> Clocks for SoC mt7621 have been properly integrated so there is no need to declare fixed clocks at all in the device tree. Remove all of them, add new device tree nodes for new mt7621-pll and mt7621-clk and update the rest of the nodes to use them. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-dts/gbpc1.dts | 11 ---- drivers/staging/mt7621-dts/mt7621.dtsi | 71 ++++++++++++-------------- 2 files changed, 34 insertions(+), 48 deletions(-) diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index a7c0d3115d72..7716d0efe524 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -100,17 +100,6 @@ partition at 50000 { }; }; -&sysclock { - compatible = "fixed-clock"; - /* This is normally 1/4 of cpuclock */ - clock-frequency = <225000000>; -}; - -&cpuclock { - compatible = "fixed-clock"; - clock-frequency = <900000000>; -}; - &pcie { pinctrl-names = "default"; pinctrl-0 = <&pcie_pins>; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 82aa93634eda..e615139d2ccb 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -1,5 +1,6 @@ #include #include +#include / { #address-cells = <1>; @@ -27,26 +28,16 @@ aliases { serial0 = &uartlite; }; - cpuclock: cpuclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* FIXME: there should be way to detect this */ - clock-frequency = <880000000>; - }; - - sysclock: sysclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* This is normally 1/4 of cpuclock */ - clock-frequency = <220000000>; + pll: pll { + compatible = "mediatek,mt7621-pll"; + #clock-cells = <1>; + clock-output-names = "cpu", "ahb", "apb"; }; - mmc_clock: mmc_clock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; + clkctrl: clkctrl { + compatible = "mediatek,mt7621-clk"; + #clock-cells = <1>; + ralink,sysctl = <&sysc>; }; mmc_fixed_3v3: fixedregulator at 0 { @@ -76,7 +67,7 @@ palmbus: palmbus at 1E000000 { #size-cells = <1>; sysc: sysc at 0 { - compatible = "mtk,mt7621-sysc"; + compatible = "mtk,mt7621-sysc", "syscon"; reg = <0x0 0x100>; }; @@ -100,8 +91,8 @@ i2c: i2c at 900 { compatible = "mediatek,mt7621-i2c"; reg = <0x900 0x100>; - clocks = <&sysclock>; - + clocks = <&clkctrl MT7621_CLK_I2C>; + clock-names = "i2c"; resets = <&rstctrl 16>; reset-names = "i2c"; @@ -118,8 +109,8 @@ i2s: i2s at a00 { compatible = "mediatek,mt7621-i2s"; reg = <0xa00 0x100>; - clocks = <&sysclock>; - + clocks = <&clkctrl MT7621_CLK_I2S>; + clock-names = "i2s"; resets = <&rstctrl 17>; reset-names = "i2s"; @@ -155,8 +146,8 @@ uartlite: uartlite at c00 { compatible = "ns16550a"; reg = <0xc00 0x100>; - clocks = <&sysclock>; - clock-frequency = <50000000>; + clocks = <&clkctrl MT7621_CLK_UART1>; + clock-names = "uart1"; interrupt-parent = <&gic>; interrupts = ; @@ -172,7 +163,7 @@ spi0: spi at b00 { compatible = "ralink,mt7621-spi"; reg = <0xb00 0x100>; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_AHB>; resets = <&rstctrl 18>; reset-names = "spi"; @@ -188,6 +179,8 @@ gdma: gdma at 2800 { compatible = "ralink,rt3883-gdma"; reg = <0x2800 0x800>; + clocks = <&clkctrl MT7621_CLK_GDMA>; + clock-names = "gdma"; resets = <&rstctrl 14>; reset-names = "dma"; @@ -205,6 +198,8 @@ hsdma: hsdma at 7000 { compatible = "mediatek,mt7621-hsdma"; reg = <0x7000 0x1000>; + clocks = <&clkctrl MT7621_CLK_HSDMA>; + clock-names = "hsdma"; resets = <&rstctrl 5>; reset-names = "hsdma"; @@ -315,11 +310,6 @@ rstctrl: rstctrl { #reset-cells = <1>; }; - clkctrl: clkctrl { - compatible = "ralink,rt2880-clock"; - #clock-cells = <1>; - }; - sdhci: sdhci at 1E130000 { status = "disabled"; @@ -338,7 +328,8 @@ sdhci: sdhci at 1E130000 { pinctrl-0 = <&sdhci_pins>; pinctrl-1 = <&sdhci_pins>; - clocks = <&mmc_clock &mmc_clock>; + clocks = <&pll MT7621_CLK_APB>, + <&pll MT7621_CLK_APB>; clock-names = "source", "hclk"; interrupt-parent = <&gic>; @@ -353,7 +344,7 @@ xhci: xhci at 1E1C0000 { 0x1e1d0700 0x0100>; reg-names = "mac", "ippc"; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_AHB>; clock-names = "sys_ck"; interrupt-parent = <&gic>; @@ -372,7 +363,7 @@ gic: interrupt-controller at 1fbc0000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&cpuclock>; + clocks = <&pll MT7621_CLK_CPU>; }; }; @@ -385,6 +376,9 @@ nand: nand at 1e003000 { 0x1e003800 0x800>; #address-cells = <1>; #size-cells = <1>; + + clocks = <&clkctrl MT7621_CLK_NAND>; + clock-names = "nand"; }; ethsys: syscon at 1e000000 { @@ -398,8 +392,9 @@ ethernet: ethernet at 1e100000 { compatible = "mediatek,mt7621-eth"; reg = <0x1e100000 0x10000>; - clocks = <&sysclock>; - clock-names = "ethif"; + clocks = <&pll MT7621_CLK_AHB>, + <&clkctrl MT7621_CLK_ETH>; + clock-names = "ethif", "eth"; #address-cells = <1>; #size-cells = <0>; @@ -532,7 +527,9 @@ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; reset-names = "pcie0", "pcie1", "pcie2"; - clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; + clocks = <&clkctrl MT7621_CLK_PCIE0>, + <&clkctrl MT7621_CLK_PCIE1>, + <&clkctrl MT7621_CLK_PCIE2>; clock-names = "pcie0", "pcie1", "pcie2"; phys = <&pcie0_phy 1>, <&pcie2_phy 0>; phy-names = "pcie-phy0", "pcie-phy2"; -- 2.25.1 From gch981213 at gmail.com Thu Nov 12 01:26:14 2020 From: gch981213 at gmail.com (Chuanhong Guo) Date: Thu, 12 Nov 2020 09:26:14 +0800 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: <20201111163013.29412-1-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: Hi! On Thu, Nov 12, 2020 at 12:30 AM Sergio Paracuellos wrote: > > This patchset ports CPU clock detection for MT7621 from OpenWrt > and adds a complete clock plan for the mt7621 SOC. > > The documentation for this SOC only talks about two registers > regarding to the clocks: > * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped > refclock. PLL and dividers used for CPU and some sort of BUS (AHB?). > * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for > all or some ip cores. > > No documentation about a probably existant set of dividers for each ip > core is included in the datasheets. So we cannot make anything better, > AFAICT. > > Looking into driver code, there is another frequency which is used in > some drivers (uart, sd...) which for any reason is always hardcoded to > 50 MHz. Taking this into account this patchset provides three main fixed > clocks to the SOC in 'mt7621-pll' which are: > - "cpu": with detected frequency (900 MHz in my board). > - "ahb": cpu / 4 = 225 Mhz. > - "apb": 50 Mhz. > > PLL controller cannot be manipulatedbecause there is no info about > how to do it. Because of this, there is nothing related with registers > in the included binding. > > It also provides a clock gate driver 'mt7621-clk' as a platform driver > to allow to enable and disable some clocks in the different ip cores. > The parent clocks for this clock gates have also set taking into account > existant device tree and driver code resulting in the followings: > - "hsdma": "ahb" > - "fe": "ahb" > - "sp_divtx": "ahb" > - "timer": "cpu" > - "int": "cpu" > - "mc": "ahb" > - "pcm": "ahb" > - "pio": "ahb" > - "gdma": "ahb" > - "nand": "ahb" > - "i2c": "ahb" > - "i2s": "ahb" > - "spi": "ahb" > - "uart1": "apb" > - "uart2": "apb" > - "uart3": "apb" > - "eth": "ahb" > - "pcie0": "ahb" > - "pcie1": "ahb" > - "pcie2": "ahb" > - "crypto": "ahb" > - "shxc": "ahb" > > There was a previous attempt of doing this here[0] but the author > did not wanted to make assumptions of a clock plan for the platform. I've already said in previous threads that clock assignment in current linux kernel is not trustworthy. I've got the clock plan for mt7621 now. (Can't share it, sorry.) Most of your clock assumptions above are incorrect. I've made a clock driver with gate support a few months ago.[0] but I don't have much time to really finish it. Maybe you could rework your clock gate driver based on it. [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 -- Regards, Chuanhong Guo From gch981213 at gmail.com Thu Nov 12 01:33:56 2020 From: gch981213 at gmail.com (Chuanhong Guo) Date: Thu, 12 Nov 2020 09:33:56 +0800 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: On Thu, Nov 12, 2020 at 9:26 AM Chuanhong Guo wrote: > > I've already said in previous threads that clock assignment in > current linux kernel is not trustworthy. > I've got the clock plan for mt7621 now. (Can't share it, sorry.) > Most of your clock assumptions above are incorrect. > I've made a clock driver with gate support a few months ago.[0] > but I don't have much time to really finish it. > Maybe you could rework your clock gate driver based on it. > > [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 hsdma/eth/pio clocks are still missing in mediatek doc and I just made them up in the driver. Correct clock frequency for them aren't really important for them to work though. And another part I didn't finish is checking clock support for every drivers mt7621 used. Many drivers don't explicitly enable the clock and may be problematic when kernel gates unused clocks. -- Regards, Chuanhong Guo From dmitry.torokhov at gmail.com Thu Nov 12 01:45:42 2020 From: dmitry.torokhov at gmail.com (Dmitry Torokhov) Date: Wed, 11 Nov 2020 17:45:42 -0800 Subject: [PATCH v3 07/11] input: raspberrypi-ts: Release firmware handle when not needed In-Reply-To: <20201104103938.1286-8-nsaenzjulienne@suse.de> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-8-nsaenzjulienne@suse.de> Message-ID: <20201112014542.GA1003057@dtor-ws> Hi Nicolas, On Wed, Nov 04, 2020 at 11:39:33AM +0100, Nicolas Saenz Julienne wrote: > Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware > interface when unbinding the device. Unless I am mistaken this driver does not really need the firmware structure past rpi_ts_probe(), and will be fine if it disappears earlier than unbind time. Thanks. > > Signed-off-by: Nicolas Saenz Julienne > > --- > > Changes since v2: > - Use devm_rpi_firmware_get(), instead of remove function > > drivers/input/touchscreen/raspberrypi-ts.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c > index ef6aaed217cf..efed0efa91d9 100644 > --- a/drivers/input/touchscreen/raspberrypi-ts.c > +++ b/drivers/input/touchscreen/raspberrypi-ts.c > @@ -134,7 +134,7 @@ static int rpi_ts_probe(struct platform_device *pdev) > return -ENOENT; > } > > - fw = rpi_firmware_get(fw_node); > + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); > of_node_put(fw_node); > if (!fw) > return -EPROBE_DEFER; > -- > 2.29.1 > -- Dmitry From sergio.paracuellos at gmail.com Thu Nov 12 05:18:27 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 12 Nov 2020 06:18:27 +0100 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: Hi Chuanhong, On Thu, Nov 12, 2020 at 2:26 AM Chuanhong Guo wrote: [snip] > > I've already said in previous threads that clock assignment in > current linux kernel is not trustworthy. > I've got the clock plan for mt7621 now. (Can't share it, sorry.) > Most of your clock assumptions above are incorrect. Well, that was of course expected, without a real clock plan this driver was only taking into account Oleksij Rempel suggestions to try to make a driver good enough to properly be maintained :). > I've made a clock driver with gate support a few months ago.[0] > but I don't have much time to really finish it. > Maybe you could rework your clock gate driver based on it. > > [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 Thanks for the link, I see there are three more clocks there with frequencies of 125, 250 and 270 Mhz. all of them having main xtal as parent. Ok, I will take this real information into account and will send v2 after a bit of more feedback comes. > -- > Regards, > Chuanhong Guo Best regards, Sergio Paracuellos From sergio.paracuellos at gmail.com Thu Nov 12 05:23:46 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 12 Nov 2020 06:23:46 +0100 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: Hi, On Thu, Nov 12, 2020 at 2:34 AM Chuanhong Guo wrote: > > On Thu, Nov 12, 2020 at 9:26 AM Chuanhong Guo wrote: > > > > I've already said in previous threads that clock assignment in > > current linux kernel is not trustworthy. > > I've got the clock plan for mt7621 now. (Can't share it, sorry.) > > Most of your clock assumptions above are incorrect. > > I've made a clock driver with gate support a few months ago.[0] > > but I don't have much time to really finish it. > > Maybe you could rework your clock gate driver based on it. > > > > [0] https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 > > hsdma/eth/pio clocks are still missing in mediatek doc and > I just made them up in the driver. Correct clock frequency for > them aren't really important for them to work though. > And another part I didn't finish is checking clock support for > every drivers mt7621 used. Many drivers don't explicitly > enable the clock and may be problematic when kernel > gates unused clocks. > Well, I think they are not important either. Also, by default gate register has all the gate bits enabled. When a gate driver is added, the kernel by default will try to disable those clocks that haven't been requested. To avoid weird behaviour because of some drivers are not using properly clocks we have the CLK_IGNORED_UNUSED, which as you can see is currently being used in my code. Using that all seems to work as expected as it is now. > -- > Regards, > Chuanhong Guo Best regards, Sergio Paracuellos From jingxiangfeng at huawei.com Thu Nov 12 06:49:24 2020 From: jingxiangfeng at huawei.com (Jing Xiangfeng) Date: Thu, 12 Nov 2020 14:49:24 +0800 Subject: [PATCH] staging: gasket: interrupt: fix the missed eventfd_ctx_put() in gasket_interrupt.c Message-ID: <20201112064924.99680-1-jingxiangfeng@huawei.com> gasket_interrupt_set_eventfd() misses to call eventfd_ctx_put() in an error path. We check interrupt is valid before calling eventfd_ctx_fdget() to fix it. There is the same issue in gasket_interrupt_clear_eventfd(), Add the missed function call to fix it. Fixes: 9a69f5087ccc ("drivers/staging: Gasket driver framework + Apex driver") Signed-off-by: Jing Xiangfeng --- drivers/staging/gasket/gasket_interrupt.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/staging/gasket/gasket_interrupt.c b/drivers/staging/gasket/gasket_interrupt.c index 2d6195f7300e..864342acfd86 100644 --- a/drivers/staging/gasket/gasket_interrupt.c +++ b/drivers/staging/gasket/gasket_interrupt.c @@ -487,14 +487,16 @@ int gasket_interrupt_system_status(struct gasket_dev *gasket_dev) int gasket_interrupt_set_eventfd(struct gasket_interrupt_data *interrupt_data, int interrupt, int event_fd) { - struct eventfd_ctx *ctx = eventfd_ctx_fdget(event_fd); - - if (IS_ERR(ctx)) - return PTR_ERR(ctx); + struct eventfd_ctx *ctx; if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts) return -EINVAL; + ctx = eventfd_ctx_fdget(event_fd); + + if (IS_ERR(ctx)) + return PTR_ERR(ctx); + interrupt_data->eventfd_ctxs[interrupt] = ctx; return 0; } @@ -505,6 +507,9 @@ int gasket_interrupt_clear_eventfd(struct gasket_interrupt_data *interrupt_data, if (interrupt < 0 || interrupt >= interrupt_data->num_interrupts) return -EINVAL; - interrupt_data->eventfd_ctxs[interrupt] = NULL; + if (interrupt_data->eventfd_ctxs[interrupt]) { + eventfd_ctx_put(interrupt_data->eventfd_ctxs[interrupt]); + interrupt_data->eventfd_ctxs[interrupt] = NULL; + } return 0; } -- 2.17.1 From nsaenzjulienne at suse.de Thu Nov 12 09:06:21 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 10:06:21 +0100 Subject: [PATCH v3 07/11] input: raspberrypi-ts: Release firmware handle when not needed In-Reply-To: <20201112014542.GA1003057@dtor-ws> References: <20201104103938.1286-1-nsaenzjulienne@suse.de> <20201104103938.1286-8-nsaenzjulienne@suse.de> <20201112014542.GA1003057@dtor-ws> Message-ID: <9e3a04f0ae76675f610bf25e6b53b4aff26afae4.camel@suse.de> On Wed, 2020-11-11 at 17:45 -0800, Dmitry Torokhov wrote: > Hi Nicolas, > > On Wed, Nov 04, 2020 at 11:39:33AM +0100, Nicolas Saenz Julienne wrote: > > Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware > > interface when unbinding the device. > > Unless I am mistaken this driver does not really need the firmware > structure past rpi_ts_probe(), and will be fine if it disappears earlier > than unbind time. Yes, I missed that. Will update it. Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From lee.jones at linaro.org Thu Nov 12 13:19:53 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:53 +0000 Subject: [PATCH 0/6] Rid i2400m driver set of W=1 issues Message-ID: <20201112131959.2213841-1-lee.jones@linaro.org> This set is part of a larger effort attempting to clean-up W=1 kernel builds, which are currently overwhelmingly riddled with niggly little warnings. This is a rebased set that went to Net before the move to Staging. Lee Jones (6): staging: net: wimax: i2400m: control: Fix some misspellings in i2400m_set_init_config()'s docs staging: net: wimax: i2400m: driver: Demote some non-conformant kernel-docs, fix others staging: net: wimax: i2400m: fw: Fix some function header misdemeanours staging: net: wimax: i2400m: netdev: Demote non-conformant function header staging: net: wimax: i2400m: tx: Fix a few kernel-doc misdemeanours staging: net: wimax: i2400m: fw: Fix incorrectly spelt function parameter in documentation drivers/staging/wimax/i2400m/control.c | 4 ++-- drivers/staging/wimax/i2400m/driver.c | 9 +++++---- drivers/staging/wimax/i2400m/fw.c | 14 +++++++++++--- drivers/staging/wimax/i2400m/netdev.c | 2 +- drivers/staging/wimax/i2400m/tx.c | 6 +++++- 5 files changed, 24 insertions(+), 11 deletions(-) Cc: "David S. Miller" Cc: devel at driverdev.osuosl.org Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: Jakub Kicinski Cc: linux-wimax at intel.com Cc: netdev at vger.kernel.org Cc: Yanir Lubetkin -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:56 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:56 +0000 Subject: [PATCH 3/6] staging: net: wimax: i2400m: fw: Fix some function header misdemeanours In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-4-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/fw.c:584: warning: Function parameter or member 'i2400m' not described in 'i2400m_bm_cmd' drivers/net/wimax/i2400m/fw.c:584: warning: Excess function parameter 'returns' description in 'i2400m_bm_cmd' drivers/net/wimax/i2400m/fw.c:646: warning: Function parameter or member 'chunk' not described in 'i2400m_download_chunk' drivers/net/wimax/i2400m/fw.c:646: warning: Function parameter or member '__chunk_len' not described in 'i2400m_download_chunk' drivers/net/wimax/i2400m/fw.c:646: warning: Excess function parameter 'buf' description in 'i2400m_download_chunk' drivers/net/wimax/i2400m/fw.c:646: warning: Excess function parameter 'buf_len' description in 'i2400m_download_chunk' drivers/net/wimax/i2400m/fw.c:1548: warning: Function parameter or member 'flags' not described in 'i2400m_dev_bootstrap' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Yanir Lubetkin Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/fw.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/staging/wimax/i2400m/fw.c b/drivers/staging/wimax/i2400m/fw.c index 6c9a41bff2e0a..9970857063374 100644 --- a/drivers/staging/wimax/i2400m/fw.c +++ b/drivers/staging/wimax/i2400m/fw.c @@ -534,6 +534,7 @@ ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode, /** * i2400m_bm_cmd - Execute a boot mode command * + * @i2400m: device descriptor * @cmd: buffer containing the command data (pointing at the header). * This data can be ANYWHERE (for USB, we will copy it to an * specific buffer). Make sure everything is in proper little @@ -566,7 +567,7 @@ ssize_t __i2400m_bm_ack_verify(struct i2400m *i2400m, int opcode, * * @flags: see I2400M_BM_CMD_* above. * - * @returns: bytes received by the notification; if < 0, an errno code + * Returns: bytes received by the notification; if < 0, an errno code * denoting an error or: * * -ERESTARTSYS The device has rebooted @@ -634,8 +635,8 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m, * i2400m_download_chunk - write a single chunk of data to the device's memory * * @i2400m: device descriptor - * @buf: the buffer to write - * @buf_len: length of the buffer to write + * @chunk: the buffer to write + * @chunk_len: length of the buffer to write * @addr: address in the device memory space * @direct: bootrom write mode * @do_csum: should a checksum validation be performed @@ -1533,6 +1534,13 @@ void i2400m_fw_put(struct i2400m_fw *i2400m_fw) * i2400m_dev_bootstrap - Bring the device to a known state and upload firmware * * @i2400m: device descriptor + * @flags: + * I2400M_BRI_SOFT: a reboot barker has been seen + * already, so don't wait for it. + * + * I2400M_BRI_NO_REBOOT: Don't send a reboot command, but wait + * for a reboot barker notification. This is a one shot; if + * the state machine needs to send a reboot command it will. * * Returns: >= 0 if ok, < 0 errno code on error. * -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:55 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:55 +0000 Subject: [PATCH 2/6] staging: net: wimax: i2400m: driver: Demote some non-conformant kernel-docs, fix others In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-3-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/driver.c:681: warning: Function parameter or member 'i2400m' not described in 'i2400m_dev_reset_handle' drivers/net/wimax/i2400m/driver.c:681: warning: Function parameter or member 'reason' not described in 'i2400m_dev_reset_handle' drivers/net/wimax/i2400m/driver.c:775: warning: Function parameter or member 'i2400m' not described in 'i2400m_init' drivers/net/wimax/i2400m/driver.c:842: warning: Function parameter or member 'bm_flags' not described in 'i2400m_setup' drivers/net/wimax/i2400m/driver.c:942: warning: Function parameter or member 'i2400m' not described in 'i2400m_release' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/driver.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/staging/wimax/i2400m/driver.c b/drivers/staging/wimax/i2400m/driver.c index dc8939ff78c0e..f5186458bb3d4 100644 --- a/drivers/staging/wimax/i2400m/driver.c +++ b/drivers/staging/wimax/i2400m/driver.c @@ -665,7 +665,7 @@ void __i2400m_dev_reset_handle(struct work_struct *ws) } -/** +/* * i2400m_dev_reset_handle - Handle a device's reset in a thread context * * Schedule a device reset handling out on a thread context, so it @@ -685,7 +685,7 @@ int i2400m_dev_reset_handle(struct i2400m *i2400m, const char *reason) EXPORT_SYMBOL_GPL(i2400m_dev_reset_handle); - /* +/* * The actual work of error recovery. * * The current implementation of error recovery is to trigger a bus reset. @@ -766,7 +766,7 @@ void i2400m_bm_buf_free(struct i2400m *i2400m) } -/** +/* * i2400m_init - Initialize a 'struct i2400m' from all zeroes * * This is a bus-generic API call. @@ -831,6 +831,7 @@ EXPORT_SYMBOL_GPL(i2400m_reset); * i2400m_setup - bus-generic setup function for the i2400m device * * @i2400m: device descriptor (bus-specific parts have been initialized) + * @bm_flags: boot mode flags * * Returns: 0 if ok, < 0 errno code on error. * @@ -933,7 +934,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags) EXPORT_SYMBOL_GPL(i2400m_setup); -/** +/* * i2400m_release - release the bus-generic driver resources * * Sends a disconnect message and undoes any setup done by i2400m_setup() -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:57 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:57 +0000 Subject: [PATCH 4/6] staging: net: wimax: i2400m: netdev: Demote non-conformant function header In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-5-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/netdev.c:583: warning: Function parameter or member 'net_dev' not described in 'i2400m_netdev_setup' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Yanir Lubetkin Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wimax/i2400m/netdev.c b/drivers/staging/wimax/i2400m/netdev.c index a7fcbceb6e6be..8339d600e77b5 100644 --- a/drivers/staging/wimax/i2400m/netdev.c +++ b/drivers/staging/wimax/i2400m/netdev.c @@ -574,7 +574,7 @@ static const struct ethtool_ops i2400m_ethtool_ops = { .get_link = ethtool_op_get_link, }; -/** +/* * i2400m_netdev_setup - Setup setup @net_dev's i2400m private data * * Called by alloc_netdev() -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:54 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:54 +0000 Subject: [PATCH 1/6] staging: net: wimax: i2400m: control: Fix some misspellings in i2400m_set_init_config()'s docs In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-2-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/control.c:1195: warning: Function parameter or member 'arg' not described in 'i2400m_set_init_config' drivers/net/wimax/i2400m/control.c:1195: warning: Excess function parameter 'arg_size' description in 'i2400m_set_init_config' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/control.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/wimax/i2400m/control.c b/drivers/staging/wimax/i2400m/control.c index fe885aa56cf37..1e270b2101e86 100644 --- a/drivers/staging/wimax/i2400m/control.c +++ b/drivers/staging/wimax/i2400m/control.c @@ -1183,11 +1183,11 @@ static int i2400m_cmd_get_state(struct i2400m *i2400m) * Set basic configuration settings * * @i2400m: device descriptor - * @args: array of pointers to the TLV headers to send for + * @arg: array of pointers to the TLV headers to send for * configuration (each followed by its payload). * TLV headers and payloads must be properly initialized, with the * right endianess (LE). - * @arg_size: number of pointers in the @args array + * @args: number of pointers in the @arg array */ static int i2400m_set_init_config(struct i2400m *i2400m, const struct i2400m_tlv_hdr **arg, -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:58 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:58 +0000 Subject: [PATCH 5/6] staging: net: wimax: i2400m: tx: Fix a few kernel-doc misdemeanours In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-6-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/tx.c:715: warning: Function parameter or member 'i2400m' not described in 'i2400m_tx' drivers/net/wimax/i2400m/tx.c:964: warning: Function parameter or member 'i2400m' not described in 'i2400m_tx_setup' drivers/net/wimax/i2400m/tx.c:1005: warning: Function parameter or member 'i2400m' not described in 'i2400m_tx_release' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Yanir Lubetkin Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/tx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/wimax/i2400m/tx.c b/drivers/staging/wimax/i2400m/tx.c index 1255302e251e4..e9436212fe54d 100644 --- a/drivers/staging/wimax/i2400m/tx.c +++ b/drivers/staging/wimax/i2400m/tx.c @@ -681,6 +681,8 @@ void i2400m_tx_close(struct i2400m *i2400m) /** * i2400m_tx - send the data in a buffer to the device * + * @i2400m: device descriptor + * * @buf: pointer to the buffer to transmit * * @buf_len: buffer size @@ -955,6 +957,8 @@ EXPORT_SYMBOL_GPL(i2400m_tx_msg_sent); /** * i2400m_tx_setup - Initialize the TX queue and infrastructure * + * @i2400m: device descriptor + * * Make sure we reset the TX sequence to zero, as when this function * is called, the firmware has been just restarted. Same rational * for tx_in, tx_out, tx_msg_size and tx_msg. We reset them since @@ -998,7 +1002,7 @@ int i2400m_tx_setup(struct i2400m *i2400m) } -/** +/* * i2400m_tx_release - Tear down the TX queue and infrastructure */ void i2400m_tx_release(struct i2400m *i2400m) -- 2.25.1 From lee.jones at linaro.org Thu Nov 12 13:19:59 2020 From: lee.jones at linaro.org (Lee Jones) Date: Thu, 12 Nov 2020 13:19:59 +0000 Subject: [PATCH 6/6] staging: net: wimax: i2400m: fw: Fix incorrectly spelt function parameter in documentation In-Reply-To: <20201112131959.2213841-1-lee.jones@linaro.org> References: <20201112131959.2213841-1-lee.jones@linaro.org> Message-ID: <20201112131959.2213841-7-lee.jones@linaro.org> Fixes the following W=1 kernel build warning(s): drivers/net/wimax/i2400m/fw.c:647: warning: Function parameter or member '__chunk_len' not described in 'i2400m_download_chunk' drivers/net/wimax/i2400m/fw.c:647: warning: Excess function parameter 'chunk_len' description in 'i2400m_download_chunk' Cc: Greg Kroah-Hartman Cc: Inaky Perez-Gonzalez Cc: linux-wimax at intel.com Cc: "David S. Miller" Cc: Jakub Kicinski Cc: Yanir Lubetkin Cc: netdev at vger.kernel.org Cc: devel at driverdev.osuosl.org Signed-off-by: Lee Jones --- drivers/staging/wimax/i2400m/fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wimax/i2400m/fw.c b/drivers/staging/wimax/i2400m/fw.c index 9970857063374..edb5eba0898b0 100644 --- a/drivers/staging/wimax/i2400m/fw.c +++ b/drivers/staging/wimax/i2400m/fw.c @@ -636,7 +636,7 @@ ssize_t i2400m_bm_cmd(struct i2400m *i2400m, * * @i2400m: device descriptor * @chunk: the buffer to write - * @chunk_len: length of the buffer to write + * @__chunk_len: length of the buffer to write * @addr: address in the device memory space * @direct: bootrom write mode * @do_csum: should a checksum validation be performed -- 2.25.1 From nsaenzjulienne at suse.de Thu Nov 12 16:36:26 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:26 +0100 Subject: [PATCH v4 08/11] input: raspberrypi-ts: Release firmware handle when not needed In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-9-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v3: - Release firmware handle in probe function Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/input/touchscreen/raspberrypi-ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index ef6aaed217cf..5000f5fd9ec3 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -160,7 +160,7 @@ static int rpi_ts_probe(struct platform_device *pdev) touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); - + rpi_firmware_put(fw); if (error || touchbuf != 0) { dev_warn(dev, "Failed to set touchbuf, %d\n", error); return error; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:18 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:18 +0100 Subject: [PATCH v4 00/11] Raspberry Pi PoE HAT fan support Message-ID: <20201112163630.17177-1-nsaenzjulienne@suse.de> The aim of this series is to add support to the fan found on RPi's PoE HAT. Some commentary on the design can be found below. But the imporant part to the people CC'd here not involved with PWM is that, in order to achieve this properly, we also have to fix the firmware interface the driver uses to communicate with the PWM bus (and many other low level functions). Specifically, we have to make sure the firmware interface isn't unbound while consumers are still up. So, patch #1 & #2 introduce reference counting in the firwmware interface driver and patches #3 to #8 update all firmware users. Patches #9 to #11 introduce the new PWM driver. I sent everything as a single series as the final version of the PWM drivers depends on the firwmare fixes, but I'll be happy to split this into two separate series if you think it's better. --- Original cover letter below --- This series aims at adding support to RPi's official PoE HAT fan[1]. The HW setup is the following: | Raspberry Pi | PoE HAT | arm core -> Mailbox -> RPi co-processor -> I2C -> Atmel MCU -> PWM -> FAN The arm cores have only access to the mailbox interface, as i2c0, even if physically accessible, is to be used solely by the co-processor (VideoCore 4/6). This series implements a PWM bus, and has pwm-fan sitting on top of it as per this discussion: https://lkml.org/lkml/2018/9/2/486. Although this design has a series of shortcomings: - It depends on a DT binding: it's not flexible if a new hat shows up with new functionality, we're not 100% sure we'll be able to expand it without breaking backwards compatibility. But without it we can't make use of DT thermal-zones, which IMO is overkill. - We're using pwm-fan, writing a hwmon driver would, again, give us more flexibility, but it's not really needed at the moment. I personally think that it's not worth the effort, it's unlikely we'll get things right in advance. And ultimately, if the RPi people come up with something new, we can always write a new driver/bindings from scratch (as in not reusing previous code). That said, I'm more than happy to change things if there is a consensus that another design will do the trick. [1] https://www.raspberrypi.org/blog/introducing-power-over-ethernet-poe-hat/ --- Changes since v3: - Split first patch, #1 introduces refcount, then #2 the devm function - Fix touchscreen function - Use kref Changes since v2: - Introduce devm_rpi_firmware_get() - Small cleanups in PWM driver Changes since v1: - Address PWM driver changes - Fix binding, now with 2 cells Nicolas Saenz Julienne (11): firmware: raspberrypi: Keep count of all consumers firmware: raspberrypi: Introduce devm_rpi_firmware_get() clk: bcm: rpi: Release firmware handle on unbind gpio: raspberrypi-exp: Release firmware handle on unbind reset: raspberrypi: Release firmware handle on unbind soc: bcm: raspberrypi-power: Release firmware handle on unbind staging: vchiq: Release firmware handle on unbind input: raspberrypi-ts: Release firmware handle when not needed dt-bindings: pwm: Add binding for RPi firmware PWM bus DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support pwm: Add Raspberry Pi Firmware based PWM bus .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 ++ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++ drivers/clk/bcm/clk-raspberrypi.c | 2 +- drivers/firmware/raspberrypi.c | 66 +++++- drivers/gpio/gpio-raspberrypi-exp.c | 2 +- drivers/input/touchscreen/raspberrypi-ts.c | 2 +- drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++ drivers/reset/reset-raspberrypi.c | 2 +- drivers/soc/bcm/raspberrypi-power.c | 2 +- .../interface/vchiq_arm/vchiq_arm.c | 2 +- .../pwm/raspberrypi,firmware-pwm.h | 13 ++ include/soc/bcm2835/raspberrypi-firmware.h | 10 + 14 files changed, 391 insertions(+), 10 deletions(-) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:19 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:19 +0100 Subject: [PATCH v4 01/11] firmware: raspberrypi: Keep count of all consumers In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-2-nsaenzjulienne@suse.de> When unbinding the firmware device we need to make sure it has no consumers left. Otherwise we'd leave them with a firmware handle pointing at freed memory. Keep a reference count of all consumers and introduce rpi_firmware_put() which will permit automatically decrease the reference count upon unbinding consumer drivers. Suggested-by: Uwe Kleine-K?nig Signed-off-by: Nicolas Saenz Julienne --- Changes since v3: - Use kref instead of waiting on refcount drivers/firmware/raspberrypi.c | 37 +++++++++++++++++++--- include/soc/bcm2835/raspberrypi-firmware.h | 2 ++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 2371d08bdd17..438e17074a97 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,8 @@ struct rpi_firmware { struct mbox_chan *chan; /* The property channel. */ struct completion c; u32 enabled; + + struct kref consumers; }; static DEFINE_MUTEX(transaction_lock); @@ -225,12 +228,27 @@ static void rpi_register_clk_driver(struct device *dev) -1, NULL, 0); } +static void rpi_firmware_delete(struct kref *kref) +{ + struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, + consumers); + + mbox_free_channel(fw->chan); + kfree(fw); +} + +void rpi_firmware_put(struct rpi_firmware *fw) +{ + kref_put(&fw->consumers, rpi_firmware_delete); +} +EXPORT_SYMBOL_GPL(rpi_firmware_put); + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpi_firmware *fw; - fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + fw = kzalloc(sizeof(*fw), GFP_KERNEL); if (!fw) return -ENOMEM; @@ -247,6 +265,7 @@ static int rpi_firmware_probe(struct platform_device *pdev) } init_completion(&fw->c); + kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -275,25 +294,35 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_hwmon = NULL; platform_device_unregister(rpi_clk); rpi_clk = NULL; - mbox_free_channel(fw->chan); + + rpi_firmware_put(fw); return 0; } /** - * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. * + * The reference to rpi_firmware has to be released with rpi_firmware_put(). + * * Returns NULL is the firmware device is not ready. */ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { struct platform_device *pdev = of_find_device_by_node(firmware_node); + struct rpi_firmware *fw; if (!pdev) return NULL; - return platform_get_drvdata(pdev); + fw = platform_get_drvdata(pdev); + if (!fw) + return NULL; + + if (!kref_get_unless_zero(&fw->consumers)) + return NULL; + + return fw; } EXPORT_SYMBOL_GPL(rpi_firmware_get); diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index cc9cdbc66403..fdfef7fe40df 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -140,6 +140,7 @@ int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); +void rpi_firmware_put(struct rpi_firmware *fw); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, @@ -154,6 +155,7 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, return -ENOSYS; } +static inline void rpi_firmware_put(struct rpi_firmware *fw) { } static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { return NULL; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:21 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:21 +0100 Subject: [PATCH v4 03/11] clk: bcm: rpi: Release firmware handle on unbind In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-4-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/clk/bcm/clk-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f89b9cfc4309..dd3b71eafabf 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -314,7 +314,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) return -ENOENT; } - firmware = rpi_firmware_get(firmware_node); + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); of_node_put(firmware_node); if (!firmware) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:24 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:24 +0100 Subject: [PATCH v4 06/11] soc: bcm: raspberrypi-power: Release firmware handle on unbind In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-7-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/soc/bcm/raspberrypi-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index 5d1aacdd84ef..068715d6e66d 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -177,7 +177,7 @@ static int rpi_power_probe(struct platform_device *pdev) return -ENODEV; } - rpi_domains->fw = rpi_firmware_get(fw_np); + rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np); of_node_put(fw_np); if (!rpi_domains->fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:23 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:23 +0100 Subject: [PATCH v4 05/11] reset: raspberrypi: Release firmware handle on unbind In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-6-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/reset/reset-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c index 02f59c06f69b..fa23db554bcf 100644 --- a/drivers/reset/reset-raspberrypi.c +++ b/drivers/reset/reset-raspberrypi.c @@ -82,7 +82,7 @@ static int rpi_reset_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(np); + fw = devm_rpi_firmware_get(&pdev->dev, np); of_node_put(np); if (!fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:22 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:22 +0100 Subject: [PATCH v4 04/11] gpio: raspberrypi-exp: Release firmware handle on unbind In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-5-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne Acked-by: Bartosz Golaszewski --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/gpio/gpio-raspberrypi-exp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index bb100e0124e6..64a552ecc2ad 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -208,7 +208,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:28 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:28 +0100 Subject: [PATCH v4 10/11] DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-11-nsaenzjulienne@suse.de> This is an example on how to enable the fan on top of RPi's official PoE hat. Signed-off-by: Nicolas Saenz Julienne --- Changes since v1: - Update patch to use 2 pwm cells arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 09a1182c2936..361db82619a4 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -5,6 +5,7 @@ #include "bcm283x-rpi-usb-peripheral.dtsi" #include +#include / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; @@ -68,6 +69,54 @@ sd_vcc_reg: sd_vcc_reg { enable-active-high; gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; }; + + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 50 150 255>; + #cooling-cells = <2>; + pwms = <&fwpwm RASPBERRYPI_FIRMWARE_PWM_POE 80000>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + trips { + threshold: trip-point at 0 { + temperature = <45000>; + hysteresis = <5000>; + type = "active"; + }; + + target: trip-point at 1 { + temperature = <50000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_hot: cpu_hot at 0 { + temperature = <55000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&threshold>; + cooling-device = <&fan 0 1>; + }; + + map1 { + trip = <&target>; + cooling-device = <&fan 1 2>; + }; + + map2 { + trip = <&cpu_hot>; + cooling-device = <&fan 2 3>; + }; + }; + }; + }; }; &ddc0 { @@ -103,6 +152,11 @@ reset: reset { compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + fwpwm: pwm { + compatible = "raspberrypi,firmware-pwm"; + #pwm-cells = <2>; + }; }; &gpio { -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:25 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:25 +0100 Subject: [PATCH v4 07/11] staging: vchiq: Release firmware handle on unbind In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-8-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index f500a7043805..6c196cade4a0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -2732,7 +2732,7 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOENT; } - drvdata->fw = rpi_firmware_get(fw_node); + drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!drvdata->fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:20 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:20 +0100 Subject: [PATCH v4 02/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-3-nsaenzjulienne@suse.de> Itroduce devm_rpi_firmware_get(), it'll simplify the firmware handling for most consumers. Suggested-by: Bartosz Golaszewski Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Introduce devm_rpi_firmware_get() drivers/firmware/raspberrypi.c | 31 +++++++++++++++++++++- include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 438e17074a97..4ab2dfdc82ad 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -237,10 +237,17 @@ static void rpi_firmware_delete(struct kref *kref) kfree(fw); } -void rpi_firmware_put(struct rpi_firmware *fw) +static void __rpi_firmware_put(void *data) { + struct rpi_firmware *fw = data; + kref_put(&fw->consumers, rpi_firmware_delete); } + +void rpi_firmware_put(struct rpi_firmware *fw) +{ + __rpi_firmware_put(fw); +} EXPORT_SYMBOL_GPL(rpi_firmware_put); static int rpi_firmware_probe(struct platform_device *pdev) @@ -326,6 +333,28 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) } EXPORT_SYMBOL_GPL(rpi_firmware_get); +/** + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. + * @firmware_node: Pointer to the firmware Device Tree node. + * + * Returns NULL is the firmware device is not ready. + */ +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + struct rpi_firmware *fw; + + fw = rpi_firmware_get(firmware_node); + if (!fw) + return NULL; + + if (devm_add_action_or_reset(dev, __rpi_firmware_put, fw)) + return NULL; + + return fw; +} +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); + static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index fdfef7fe40df..73ad784fca96 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -142,6 +142,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); void rpi_firmware_put(struct rpi_firmware *fw); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -160,6 +162,12 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware { return NULL; } + +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + return NULL; +} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:29 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:29 +0100 Subject: [PATCH v4 11/11] pwm: Add Raspberry Pi Firmware based PWM bus In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-12-nsaenzjulienne@suse.de> Adds support to control the PWM bus available in official Raspberry Pi PoE HAT. Only RPi's co-processor has access to it, so commands have to be sent through RPi's firmware mailbox interface. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get() - Rename driver - Small cleanups Changes since v1: - Use default pwm bindings and get rid of xlate() function - Correct spelling errors - Correct apply() function - Round values - Fix divisions in arm32 mode - Small cleanups drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b2a87fd7e8fb..3445984a5a50 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -409,6 +409,15 @@ config PWM_PXA To compile this driver as a module, choose M here: the module will be called pwm-pxa. +config PWM_RASPBERRYPI_POE + tristate "Raspberry Pi Firwmware PoE Hat PWM support" + # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only + # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + config PWM_RCAR tristate "Renesas R-Car PWM support" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 18b89d7fd092..ed28d7bd4c64 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c new file mode 100644 index 000000000000..91cd826a36f3 --- /dev/null +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020 Nicolas Saenz Julienne + * For more information on Raspberry Pi's PoE hat see: + * https://www.raspberrypi.org/products/poe-hat/ + * + * Limitations: + * - No disable bit, so a disabled PWM is simulated by duty_cycle 0 + * - Only normal polarity + * - Fixed 12.5 kHz period + * + * The current period is completed when HW is reconfigured. + */ + +#include +#include +#include +#include + +#include +#include + +#define RPI_PWM_MAX_DUTY 255 +#define RPI_PWM_PERIOD_NS 80000 /* 12.5 kHz */ + +#define RPI_PWM_CUR_DUTY_REG 0x0 +#define RPI_PWM_DEF_DUTY_REG 0x1 + +struct raspberrypi_pwm { + struct rpi_firmware *firmware; + struct pwm_chip chip; + unsigned int duty_cycle; +}; + +struct raspberrypi_pwm_prop { + __le32 reg; + __le32 val; + __le32 ret; +} __packed; + +static inline struct raspberrypi_pwm *to_raspberrypi_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct raspberrypi_pwm, chip); +} + +static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, + u32 reg, u32 val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = cpu_to_le32(reg), + .val = cpu_to_le32(val), + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + return 0; +} + +static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, + u32 reg, u32 *val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = reg + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + *val = le32_to_cpu(msg.val); + + return 0; +} + +static void raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + + state->period = RPI_PWM_PERIOD_NS; + state->duty_cycle = DIV_ROUND_CLOSEST(rpipwm->duty_cycle * RPI_PWM_PERIOD_NS, + RPI_PWM_MAX_DUTY); + state->enabled = !!(rpipwm->duty_cycle); + state->polarity = PWM_POLARITY_NORMAL; +} + +static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + unsigned int duty_cycle; + int ret; + + if (state->period < RPI_PWM_PERIOD_NS || + state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) + duty_cycle = 0; + else if (state->duty_cycle < RPI_PWM_PERIOD_NS) + duty_cycle = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * RPI_PWM_MAX_DUTY, + RPI_PWM_PERIOD_NS); + else + duty_cycle = RPI_PWM_MAX_DUTY; + + if (duty_cycle == rpipwm->duty_cycle) + return 0; + + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set duty cycle: %d\n", ret); + return ret; + } + + /* + * This sets the default duty cycle after resetting the board, we + * updated it every time to mimic Raspberry Pi's downstream's driver + * behaviour. + */ + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_DEF_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set default duty cycle: %d\n", ret); + return ret; + } + + rpipwm->duty_cycle = duty_cycle; + + return 0; +} + +static const struct pwm_ops raspberrypi_pwm_ops = { + .get_state = raspberrypi_pwm_get_state, + .apply = raspberrypi_pwm_apply, + .owner = THIS_MODULE, +}; + +static int raspberrypi_pwm_probe(struct platform_device *pdev) +{ + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_pwm *rpipwm; + int ret; + + firmware_node = of_get_parent(dev->of_node); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); + of_node_put(firmware_node); + if (!firmware) + return -EPROBE_DEFER; + + rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL); + if (!rpipwm) + return -ENOMEM; + + rpipwm->firmware = firmware; + rpipwm->chip.dev = dev; + rpipwm->chip.ops = &raspberrypi_pwm_ops; + rpipwm->chip.base = -1; + rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; + + platform_set_drvdata(pdev, rpipwm); + + ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + &rpipwm->duty_cycle); + if (ret) { + dev_err(dev, "Failed to get duty cycle: %d\n", ret); + return ret; + } + + return pwmchip_add(&rpipwm->chip); +} + +static int raspberrypi_pwm_remove(struct platform_device *pdev) +{ + struct raspberrypi_pwm *rpipwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&rpipwm->chip); +} + +static const struct of_device_id raspberrypi_pwm_of_match[] = { + { .compatible = "raspberrypi,firmware-pwm", }, + { } +}; +MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match); + +static struct platform_driver raspberrypi_pwm_driver = { + .driver = { + .name = "raspberrypi-pwm", + .of_match_table = raspberrypi_pwm_of_match, + }, + .probe = raspberrypi_pwm_probe, + .remove = raspberrypi_pwm_remove, +}; +module_platform_driver(raspberrypi_pwm_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne "); +MODULE_DESCRIPTION("Raspberry Pi Firwmare Based PWM Bus Driver"); +MODULE_LICENSE("GPL v2"); -- 2.29.2 From nsaenzjulienne at suse.de Thu Nov 12 16:36:27 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Thu, 12 Nov 2020 17:36:27 +0100 Subject: [PATCH v4 09/11] dt-bindings: pwm: Add binding for RPi firmware PWM bus In-Reply-To: <20201112163630.17177-1-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> Message-ID: <20201112163630.17177-10-nsaenzjulienne@suse.de> The PWM bus controlling the fan in RPi's official PoE hat can only be controlled by the board's co-processor. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Rob Herring --- Changes since v3: - Fix example Changes since v1: - Update bindings to use 2 #pwm-cells .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 +++++++++++++++++++ .../pwm/raspberrypi,firmware-pwm.h | 13 ++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-pwm.h diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index a2c63c8b1d10..38be3ff69609 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -64,6 +64,21 @@ properties: - compatible - "#reset-cells" + pwm: + type: object + + properties: + compatible: + const: raspberrypi,firmware-pwm + + "#pwm-cells": + # See pwm.yaml in this directory for a description of the cells format. + const: 2 + + required: + - compatible + - "#pwm-cells" + additionalProperties: false required: @@ -87,5 +102,10 @@ examples: compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + pwm: pwm { + compatible = "raspberrypi,firmware-pwm"; + #pwm-cells = <2>; + }; }; ... diff --git a/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h b/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h new file mode 100644 index 000000000000..27c5ce68847b --- /dev/null +++ b/include/dt-bindings/pwm/raspberrypi,firmware-pwm.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H + +#define RASPBERRYPI_FIRMWARE_PWM_POE 0 +#define RASPBERRYPI_FIRMWARE_PWM_NUM 1 + +#endif -- 2.29.2 From digetx at gmail.com Thu Nov 12 16:59:36 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 12 Nov 2020 19:59:36 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201111115534.GA4847@sirena.org.uk> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> Message-ID: 11.11.2020 14:55, Mark Brown ?????: > On Wed, Nov 11, 2020 at 12:23:41AM +0300, Dmitry Osipenko wrote: >> 10.11.2020 23:32, Mark Brown ?????: > >>>>> + if (!device_property_present(dc->dev, "core-supply")) >>>>> + return; > >>>> This is a potentially heavy operation, so I think we should avoid that >>>> here. How about you use devm_regulator_get_optional() in ->probe()? That >>>> returns -ENODEV if no regulator was specified, in which case you can set >>>> dc->core_reg = NULL and use that as the condition here. > >>> Or enumerate the configurable voltages after getting the regulator and >>> handle that appropriately which would be more robust in case there's >>> missing or unusual constraints. > >> I already changed that code to use regulator_get_optional() for v2. > > That doesn't look entirely appropriate given that the core does most > likely require some kind of power to operate. We will need to do this because older DTBs won't have that regulator and we want to keep them working. Also, some device-trees won't have that regulator anyways because board schematics isn't available, and thus, we can't fix them. >> Regarding the enumerating supported voltage.. I think this should be >> done by the OPP core, but regulator core doesn't work well if >> regulator_get() is invoked more than one time for the same device, at >> least there is a loud debugfs warning about an already existing > > I don't understand why this would be an issue - if nothing else the core > could just offer an interface to trigger the check. It's not an issue, I just described what happens when device driver tries to get a regulator twice. There was an issue once that check is added to the regulator core code. But perhaps not worth to discuss it for now because I don't remember details. >> directory for a regulator. It's easy to check whether the debug >> directory exists before creating it, like thermal framework does it for >> example, but then there were some other more difficult issues.. I don't >> recall what they were right now. Perhaps will be easier to simply get a >> error from regulator_set_voltage() for now because it shouldn't ever >> happen in practice, unless device-tree has wrong constraints. > > The constraints might not be wrong, there might be some board which has > a constraint somewhere for > In this case board's DT shouldn't specify unsupportable OPPs. From broonie at kernel.org Thu Nov 12 17:16:00 2020 From: broonie at kernel.org (Mark Brown) Date: Thu, 12 Nov 2020 17:16:00 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> Message-ID: <20201112171600.GD4742@sirena.org.uk> On Thu, Nov 12, 2020 at 07:59:36PM +0300, Dmitry Osipenko wrote: > 11.11.2020 14:55, Mark Brown ?????: > > On Wed, Nov 11, 2020 at 12:23:41AM +0300, Dmitry Osipenko wrote: > >> I already changed that code to use regulator_get_optional() for v2. > > That doesn't look entirely appropriate given that the core does most > > likely require some kind of power to operate. > We will need to do this because older DTBs won't have that regulator and > we want to keep them working. > Also, some device-trees won't have that regulator anyways because board > schematics isn't available, and thus, we can't fix them. This is what dummy supplies are for? > >> Regarding the enumerating supported voltage.. I think this should be > >> done by the OPP core, but regulator core doesn't work well if > >> regulator_get() is invoked more than one time for the same device, at > >> least there is a loud debugfs warning about an already existing > > I don't understand why this would be an issue - if nothing else the core > > could just offer an interface to trigger the check. > It's not an issue, I just described what happens when device driver > tries to get a regulator twice. > There was an issue once that check is added to the regulator core code. > But perhaps not worth to discuss it for now because I don't remember > details. So there's no known obstacle to putting enumeration of supported voltages into the OPP core then? I'm a bit confused here. > >> directory for a regulator. It's easy to check whether the debug > >> directory exists before creating it, like thermal framework does it for > >> example, but then there were some other more difficult issues.. I don't > >> recall what they were right now. Perhaps will be easier to simply get a > >> error from regulator_set_voltage() for now because it shouldn't ever > >> happen in practice, unless device-tree has wrong constraints. > > The constraints might not be wrong, there might be some board which has > > a constraint somewhere for > In this case board's DT shouldn't specify unsupportable OPPs. Ah, so each board duplicates the OPP tables then, or there's an expectation that if there's some limit then they'll copy and modify the table? If that's the case then it's a bit redundant to do filtering indeed. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From bgolaszewski at baylibre.com Thu Nov 12 17:25:46 2020 From: bgolaszewski at baylibre.com (Bartosz Golaszewski) Date: Thu, 12 Nov 2020 18:25:46 +0100 Subject: [PATCH v4 02/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <20201112163630.17177-3-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> <20201112163630.17177-3-nsaenzjulienne@suse.de> Message-ID: On Thu, Nov 12, 2020 at 5:44 PM Nicolas Saenz Julienne wrote: > > Itroduce devm_rpi_firmware_get(), it'll simplify the firmware handling > for most consumers. > > Suggested-by: Bartosz Golaszewski > Signed-off-by: Nicolas Saenz Julienne > --- > > Changes since v2: > - Introduce devm_rpi_firmware_get() > > drivers/firmware/raspberrypi.c | 31 +++++++++++++++++++++- > include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++ > 2 files changed, 38 insertions(+), 1 deletion(-) > > diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c > index 438e17074a97..4ab2dfdc82ad 100644 > --- a/drivers/firmware/raspberrypi.c > +++ b/drivers/firmware/raspberrypi.c > @@ -237,10 +237,17 @@ static void rpi_firmware_delete(struct kref *kref) > kfree(fw); > } > > -void rpi_firmware_put(struct rpi_firmware *fw) > +static void __rpi_firmware_put(void *data) > { The '__' prefix is very vague and usually used for unlocked variants of functions. The casting to void * in rpi_firmware_put() is also unneeded. I would much prefer that the devres release callback be called devm_rpi_firmware_put() and that it call rpi_firmware_put() which would then call kref_put(). Bartosz > + struct rpi_firmware *fw = data; > + > kref_put(&fw->consumers, rpi_firmware_delete); > } > + > +void rpi_firmware_put(struct rpi_firmware *fw) > +{ > + __rpi_firmware_put(fw); > +} > EXPORT_SYMBOL_GPL(rpi_firmware_put); > > static int rpi_firmware_probe(struct platform_device *pdev) > @@ -326,6 +333,28 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) > } > EXPORT_SYMBOL_GPL(rpi_firmware_get); > > +/** > + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. > + * @firmware_node: Pointer to the firmware Device Tree node. > + * > + * Returns NULL is the firmware device is not ready. > + */ > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node) > +{ > + struct rpi_firmware *fw; > + > + fw = rpi_firmware_get(firmware_node); > + if (!fw) > + return NULL; > + > + if (devm_add_action_or_reset(dev, __rpi_firmware_put, fw)) > + return NULL; > + > + return fw; > +} > +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); > + > static const struct of_device_id rpi_firmware_of_match[] = { > { .compatible = "raspberrypi,bcm2835-firmware", }, > {}, > diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h > index fdfef7fe40df..73ad784fca96 100644 > --- a/include/soc/bcm2835/raspberrypi-firmware.h > +++ b/include/soc/bcm2835/raspberrypi-firmware.h > @@ -142,6 +142,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, > void *data, size_t tag_size); > void rpi_firmware_put(struct rpi_firmware *fw); > struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); > +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node); > #else > static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, > void *data, size_t len) > @@ -160,6 +162,12 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware > { > return NULL; > } > + > +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, > + struct device_node *firmware_node) > +{ > + return NULL; > +} > #endif > > #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ > -- > 2.29.2 > From andy.shevchenko at gmail.com Thu Nov 12 17:52:14 2020 From: andy.shevchenko at gmail.com (Andy Shevchenko) Date: Thu, 12 Nov 2020 19:52:14 +0200 Subject: [PATCH v4 01/11] firmware: raspberrypi: Keep count of all consumers In-Reply-To: <20201112163630.17177-2-nsaenzjulienne@suse.de> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> <20201112163630.17177-2-nsaenzjulienne@suse.de> Message-ID: On Thu, Nov 12, 2020 at 6:40 PM Nicolas Saenz Julienne wrote: > > When unbinding the firmware device we need to make sure it has no > consumers left. Otherwise we'd leave them with a firmware handle > pointing at freed memory. > > Keep a reference count of all consumers and introduce rpi_firmware_put() > which will permit automatically decrease the reference count upon > unbinding consumer drivers. ... > /** > - * rpi_firmware_get - Get pointer to rpi_firmware structure. > * @firmware_node: Pointer to the firmware Device Tree node. > * > + * The reference to rpi_firmware has to be released with rpi_firmware_put(). > + * > * Returns NULL is the firmware device is not ready. > */ > struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) > { > struct platform_device *pdev = of_find_device_by_node(firmware_node); > + struct rpi_firmware *fw; > > if (!pdev) > return NULL; > > - return platform_get_drvdata(pdev); > + fw = platform_get_drvdata(pdev); > + if (!fw) > + return NULL; > + > + if (!kref_get_unless_zero(&fw->consumers)) > + return NULL; Don't we have a more traditional way of doing this, i.e. try_module_get() coupled with get_device() ? > + return fw; > } -- With Best Regards, Andy Shevchenko From digetx at gmail.com Thu Nov 12 19:16:14 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 12 Nov 2020 22:16:14 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201112171600.GD4742@sirena.org.uk> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> Message-ID: 12.11.2020 20:16, Mark Brown ?????: > On Thu, Nov 12, 2020 at 07:59:36PM +0300, Dmitry Osipenko wrote: >> 11.11.2020 14:55, Mark Brown ?????: >>> On Wed, Nov 11, 2020 at 12:23:41AM +0300, Dmitry Osipenko wrote: > >>>> I already changed that code to use regulator_get_optional() for v2. > >>> That doesn't look entirely appropriate given that the core does most >>> likely require some kind of power to operate. > >> We will need to do this because older DTBs won't have that regulator and >> we want to keep them working. > >> Also, some device-trees won't have that regulator anyways because board >> schematics isn't available, and thus, we can't fix them. > > This is what dummy supplies are for? But it's not allowed to change voltage of a dummy regulator, is it intentional? >>>> Regarding the enumerating supported voltage.. I think this should be >>>> done by the OPP core, but regulator core doesn't work well if >>>> regulator_get() is invoked more than one time for the same device, at >>>> least there is a loud debugfs warning about an already existing > >>> I don't understand why this would be an issue - if nothing else the core >>> could just offer an interface to trigger the check. > >> It's not an issue, I just described what happens when device driver >> tries to get a regulator twice. > >> There was an issue once that check is added to the regulator core code. >> But perhaps not worth to discuss it for now because I don't remember >> details. > > So there's no known obstacle to putting enumeration of supported > voltages into the OPP core then? I'm a bit confused here. It's an obstacle if both OPP and device driver need to get the same regulator. Like in the case of this DRM driver, which need to control the voltage instead of allowing OPP core to do it. Please notice that devm_tegra_dc_opp_table_init() of this patch doesn't use dev_pm_opp_set_regulators(), which would allow OPP core to filter out unsupported OPPs. But then OPP core will need need to get an already requested regulator and this doesn't work well. >>>> directory for a regulator. It's easy to check whether the debug >>>> directory exists before creating it, like thermal framework does it for >>>> example, but then there were some other more difficult issues.. I don't >>>> recall what they were right now. Perhaps will be easier to simply get a >>>> error from regulator_set_voltage() for now because it shouldn't ever >>>> happen in practice, unless device-tree has wrong constraints. > >>> The constraints might not be wrong, there might be some board which has >>> a constraint somewhere for > >> In this case board's DT shouldn't specify unsupportable OPPs. > > Ah, so each board duplicates the OPP tables then, or there's an > expectation that if there's some limit then they'll copy and modify the > table? If that's the case then it's a bit redundant to do filtering > indeed. I think this is not strictly defined. Either way will work, although perhaps it should be more preferred that unsupported OPPs aren't present in a device-tree. From digetx at gmail.com Thu Nov 12 19:57:27 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 12 Nov 2020 22:57:27 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> Message-ID: <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> 11.11.2020 14:38, Ulf Hansson ?????: > On Sun, 8 Nov 2020 at 13:19, Dmitry Osipenko wrote: >> >> 05.11.2020 18:22, Dmitry Osipenko ?????: >>> 05.11.2020 12:45, Ulf Hansson ?????: >>> ... >>>> I need some more time to review this, but just a quick check found a >>>> few potential issues... >>> >>> Thank you for starting the review! I'm pretty sure it will take a couple >>> revisions until all the questions will be resolved :) >>> >>>> The "core-supply", that you specify as a regulator for each >>>> controller's device node, is not the way we describe power domains. >>>> Instead, it seems like you should register a power-domain provider >>>> (with the help of genpd) and implement the ->set_performance_state() >>>> callback for it. Each device node should then be hooked up to this >>>> power-domain, rather than to a "core-supply". For DT bindings, please >>>> have a look at Documentation/devicetree/bindings/power/power-domain.yaml >>>> and Documentation/devicetree/bindings/power/power_domain.txt. >>>> >>>> In regards to the "sync state" problem (preventing to change >>>> performance states until all consumers have been attached), this can >>>> then be managed by the genpd provider driver instead. >>> >>> I'll need to take a closer look at GENPD, thank you for the suggestion. >>> >>> Sounds like a software GENPD driver which manages clocks and voltages >>> could be a good idea, but it also could be an unnecessary >>> over-engineering. Let's see.. >>> >> >> Hello Ulf and all, >> >> I took a detailed look at the GENPD and tried to implement it. Here is >> what was found: >> >> 1. GENPD framework doesn't aggregate performance requests from the >> attached devices. This means that if deviceA requests performance state >> 10 and then deviceB requests state 3, then framework will set domain's >> state to 3 instead of 10. >> >> https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L376 > > As Viresh also stated, genpd does aggregate the votes. It even > performs aggregation hierarchy (a genpd is allowed to have parent(s) > to model a topology). Yes, I already found and fixed the bug which confused me previously and it's working well now. >> 2. GENPD framework has a sync() callback in the genpd.domain structure, >> but this callback isn't allowed to be used by the GENPD implementation. >> The GENPD framework always overrides that callback for its own needs. >> Hence GENPD doesn't allow to solve the bootstrapping >> state-synchronization problem in a nice way. >> >> https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L2606 > > That ->sync() callback isn't the callback you are looking for, it's a > PM domain specific callback - and has other purposes. > > To solve the problem you refer to, your genpd provider driver (a > platform driver) should assign its ->sync_state() callback. The > ->sync_state() callback will be invoked, when all consumer devices > have been attached (and probed) to their corresponding provider. > > You may have a look at drivers/cpuidle/cpuidle-psci-domain.c, to see > an example of how this works. If there is anything unclear, just tell > me and I will try to help. Indeed, thank you for the clarification. This variant works well. >> 3. Tegra doesn't have a dedicated hardware power-controller for the core >> domain, instead there is only an external voltage regulator. Hence we >> will need to create a phony device-tree node for the virtual power >> domain, which is probably a wrong thing to do. > > No, this is absolutely the correct thing to do. > > This isn't a virtual power domain, it's a real power domain. You only > happen to model the control of it as a regulator, as it fits nicely > with that for *this* SoC. Don't get me wrong, that's fine as long as > the supply is specified only in the power-domain provider node. > > On another SoC, you might have a different FW interface for the power > domain provider that doesn't fit well with the regulator. When that > happens, all you need to do is to implement a new power domain > provider and potentially re-define the power domain topology. More > importantly, you don't need to re-invent yet another slew of device > specific bindings - for each SoC. > >> >> === >> >> Perhaps it should be possible to create some hacks to work around >> bullets 2 and 3 in order to achieve what we need for DVFS on Tegra, but >> bullet 1 isn't solvable without changing how the GENPD core works. >> >> Altogether, the GENPD in its current form is a wrong abstraction for a >> system-wide DVFS in a case where multiple devices share power domain and >> this domain is a voltage regulator. The regulator framework is the >> correct abstraction in this case for today. > > Well, I admit it's a bit complex. But it solves the problem in a > nicely abstracted way that should work for everybody, at least in my > opinion. The OPP framework supports both voltage regulator and power domain, hiding the implementation details from drivers. This means that OPP API usage will be the same regardless of what approach (regulator or power domain) is used for a particular SoC. > Although, let's not exclude that there are pieces missing in genpd or > the opp layer, as this DVFS feature is rather new - but then we should > just extend/fix it. Will be nice to have a per-device GENPD performance stats. Thierry, could you please let me know what do you think about replacing regulator with the power domain? Do you think it's a worthwhile change? The difference in comparison to using voltage regulator directly is minimal, basically the core-supply phandle is replaced is replaced with a power-domain phandle in a device tree. The only thing which makes me feel a bit uncomfortable is that there is no real hardware node for the power domain node in a device-tree. From broonie at kernel.org Thu Nov 12 20:01:23 2020 From: broonie at kernel.org (Mark Brown) Date: Thu, 12 Nov 2020 20:01:23 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> Message-ID: <20201112200123.GF4742@sirena.org.uk> On Thu, Nov 12, 2020 at 10:16:14PM +0300, Dmitry Osipenko wrote: > 12.11.2020 20:16, Mark Brown ?????: > > On Thu, Nov 12, 2020 at 07:59:36PM +0300, Dmitry Osipenko wrote: > >> Also, some device-trees won't have that regulator anyways because board > >> schematics isn't available, and thus, we can't fix them. > > This is what dummy supplies are for? > But it's not allowed to change voltage of a dummy regulator, is it > intentional? Of course not, we can't know if the requested new voltage is valid - the driver would have to have explict support for handling situations where it's not possible to change the voltage (which it can detect through enumerating the values it wants to set at startup). [Requesting the same supply multiple times] > > So there's no known obstacle to putting enumeration of supported > > voltages into the OPP core then? I'm a bit confused here. > It's an obstacle if both OPP and device driver need to get the same > regulator. Like in the case of this DRM driver, which need to control > the voltage instead of allowing OPP core to do it. It wasn't entirely deliberate but the warnings have proven useful in catching bugs (eg, leaked regulator requests). The general thought is that if two things both claim to control the same supply on a consumer then they really ought to be coordinating with each other. > Please notice that devm_tegra_dc_opp_table_init() of this patch doesn't > use dev_pm_opp_set_regulators(), which would allow OPP core to filter > out unsupported OPPs. But then OPP core will need need to get an already > requested regulator and this doesn't work well. There is nothing stopping us adding a variant of that call which passes in the regulators that were acquired by the caller rather than having the OPP core do the requesting, or equally the OPP core could provide a mechanism for the caller to get the regulators that were requested. > > Ah, so each board duplicates the OPP tables then, or there's an > > expectation that if there's some limit then they'll copy and modify the > > table? If that's the case then it's a bit redundant to do filtering > > indeed. > I think this is not strictly defined. Either way will work, although > perhaps it should be more preferred that unsupported OPPs aren't present > in a device-tree. OTOH that does mean that if there's an updated information on OPPs (new ones added, old ones determined to be unstable) then you can't just update a central place. It depends if the OPPs are thought of as describing the SoC or the system as a whole I guess. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From thierry.reding at gmail.com Thu Nov 12 20:43:58 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Thu, 12 Nov 2020 21:43:58 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> Message-ID: <20201112204358.GA1027187@ulmo> On Thu, Nov 12, 2020 at 10:57:27PM +0300, Dmitry Osipenko wrote: > 11.11.2020 14:38, Ulf Hansson ?????: > > On Sun, 8 Nov 2020 at 13:19, Dmitry Osipenko wrote: > >> > >> 05.11.2020 18:22, Dmitry Osipenko ?????: > >>> 05.11.2020 12:45, Ulf Hansson ?????: > >>> ... > >>>> I need some more time to review this, but just a quick check found a > >>>> few potential issues... > >>> > >>> Thank you for starting the review! I'm pretty sure it will take a couple > >>> revisions until all the questions will be resolved :) > >>> > >>>> The "core-supply", that you specify as a regulator for each > >>>> controller's device node, is not the way we describe power domains. > >>>> Instead, it seems like you should register a power-domain provider > >>>> (with the help of genpd) and implement the ->set_performance_state() > >>>> callback for it. Each device node should then be hooked up to this > >>>> power-domain, rather than to a "core-supply". For DT bindings, please > >>>> have a look at Documentation/devicetree/bindings/power/power-domain.yaml > >>>> and Documentation/devicetree/bindings/power/power_domain.txt. > >>>> > >>>> In regards to the "sync state" problem (preventing to change > >>>> performance states until all consumers have been attached), this can > >>>> then be managed by the genpd provider driver instead. > >>> > >>> I'll need to take a closer look at GENPD, thank you for the suggestion. > >>> > >>> Sounds like a software GENPD driver which manages clocks and voltages > >>> could be a good idea, but it also could be an unnecessary > >>> over-engineering. Let's see.. > >>> > >> > >> Hello Ulf and all, > >> > >> I took a detailed look at the GENPD and tried to implement it. Here is > >> what was found: > >> > >> 1. GENPD framework doesn't aggregate performance requests from the > >> attached devices. This means that if deviceA requests performance state > >> 10 and then deviceB requests state 3, then framework will set domain's > >> state to 3 instead of 10. > >> > >> https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L376 > > > > As Viresh also stated, genpd does aggregate the votes. It even > > performs aggregation hierarchy (a genpd is allowed to have parent(s) > > to model a topology). > > Yes, I already found and fixed the bug which confused me previously and > it's working well now. > > >> 2. GENPD framework has a sync() callback in the genpd.domain structure, > >> but this callback isn't allowed to be used by the GENPD implementation. > >> The GENPD framework always overrides that callback for its own needs. > >> Hence GENPD doesn't allow to solve the bootstrapping > >> state-synchronization problem in a nice way. > >> > >> https://elixir.bootlin.com/linux/v5.10-rc2/source/drivers/base/power/domain.c#L2606 > > > > That ->sync() callback isn't the callback you are looking for, it's a > > PM domain specific callback - and has other purposes. > > > > To solve the problem you refer to, your genpd provider driver (a > > platform driver) should assign its ->sync_state() callback. The > > ->sync_state() callback will be invoked, when all consumer devices > > have been attached (and probed) to their corresponding provider. > > > > You may have a look at drivers/cpuidle/cpuidle-psci-domain.c, to see > > an example of how this works. If there is anything unclear, just tell > > me and I will try to help. > > Indeed, thank you for the clarification. This variant works well. > > >> 3. Tegra doesn't have a dedicated hardware power-controller for the core > >> domain, instead there is only an external voltage regulator. Hence we > >> will need to create a phony device-tree node for the virtual power > >> domain, which is probably a wrong thing to do. > > > > No, this is absolutely the correct thing to do. > > > > This isn't a virtual power domain, it's a real power domain. You only > > happen to model the control of it as a regulator, as it fits nicely > > with that for *this* SoC. Don't get me wrong, that's fine as long as > > the supply is specified only in the power-domain provider node. > > > > On another SoC, you might have a different FW interface for the power > > domain provider that doesn't fit well with the regulator. When that > > happens, all you need to do is to implement a new power domain > > provider and potentially re-define the power domain topology. More > > importantly, you don't need to re-invent yet another slew of device > > specific bindings - for each SoC. > > > >> > >> === > >> > >> Perhaps it should be possible to create some hacks to work around > >> bullets 2 and 3 in order to achieve what we need for DVFS on Tegra, but > >> bullet 1 isn't solvable without changing how the GENPD core works. > >> > >> Altogether, the GENPD in its current form is a wrong abstraction for a > >> system-wide DVFS in a case where multiple devices share power domain and > >> this domain is a voltage regulator. The regulator framework is the > >> correct abstraction in this case for today. > > > > Well, I admit it's a bit complex. But it solves the problem in a > > nicely abstracted way that should work for everybody, at least in my > > opinion. > > The OPP framework supports both voltage regulator and power domain, > hiding the implementation details from drivers. This means that OPP API > usage will be the same regardless of what approach (regulator or power > domain) is used for a particular SoC. > > > Although, let's not exclude that there are pieces missing in genpd or > > the opp layer, as this DVFS feature is rather new - but then we should > > just extend/fix it. > > Will be nice to have a per-device GENPD performance stats. > > Thierry, could you please let me know what do you think about replacing > regulator with the power domain? Do you think it's a worthwhile change? > > The difference in comparison to using voltage regulator directly is > minimal, basically the core-supply phandle is replaced is replaced with > a power-domain phandle in a device tree. These new power-domain handles would have to be added to devices that potentially already have a power-domain handle, right? Isn't that going to cause issues? I vaguely recall that we already have multiple power domains for the XUSB controller and we have to jump through extra hoops to make that work. > The only thing which makes me feel a bit uncomfortable is that there is > no real hardware node for the power domain node in a device-tree. Could we anchor the new power domain at the PMC for example? That would allow us to avoid the "virtual" node. On the other hand, if we were to use a regulator, we'd be adding a node for that, right? So isn't this effectively going to be the same node if we use a power domain? Both software constructs are using the same voltage regulator, so they should be able to be described by the same device tree node, shouldn't they? Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From digetx at gmail.com Thu Nov 12 22:14:45 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 13 Nov 2020 01:14:45 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201112204358.GA1027187@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> <20201112204358.GA1027187@ulmo> Message-ID: <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> 12.11.2020 23:43, Thierry Reding ?????: >> The difference in comparison to using voltage regulator directly is >> minimal, basically the core-supply phandle is replaced is replaced with >> a power-domain phandle in a device tree. > These new power-domain handles would have to be added to devices that > potentially already have a power-domain handle, right? Isn't that going > to cause issues? I vaguely recall that we already have multiple power > domains for the XUSB controller and we have to jump through extra hoops > to make that work. I modeled the core PD as a parent of the PMC sub-domains, which presumably is a correct way to represent the domains topology. https://gist.github.com/digetx/dfd92c7f7e0aa6cef20403c4298088d7 >> The only thing which makes me feel a bit uncomfortable is that there is >> no real hardware node for the power domain node in a device-tree. > Could we anchor the new power domain at the PMC for example? That would > allow us to avoid the "virtual" node. I had a thought about using PMC for the core domain, but not sure whether it will be an entirely correct hardware description. Although, it will be nice to have it this way. This is what Tegra TRM says about PMC: "The Power Management Controller (PMC) block interacts with an external or Power Manager Unit (PMU). The PMC mostly controls the entry and exit of the system from different sleep modes. It provides power-gating controllers for SOC and CPU power-islands and also provides scratch storage to save some of the context during sleep modes (when CPU and/or SOC power rails are off). Additionally, PMC interacts with the external Power Manager Unit (PMU)." The core voltage regulator is a part of the PMU. Not all core SoC devices are behind PMC, IIUC. > On the other hand, if we were to > use a regulator, we'd be adding a node for that, right? So isn't this > effectively going to be the same node if we use a power domain? Both > software constructs are using the same voltage regulator, so they should > be able to be described by the same device tree node, shouldn't they? I'm not exactly sure what you're meaning by "use a regulator" and "we'd be adding a node for that", could you please clarify? This v1 approach uses a core-supply phandle (i.e. regulator is used), it doesn't require extra nodes. From tabot.kevin at gmail.com Thu Nov 12 22:33:35 2020 From: tabot.kevin at gmail.com (Tabot Kevin) Date: Thu, 12 Nov 2020 23:33:35 +0100 Subject: [PATCH] staging: greybus: Fixed issues with alignment to open parenthesis. Message-ID: <20201112223331.GA1681@tabot> This patch fixes the following: - Made sure alignment matched open parenthesis. Signed-off-by: Tabot Kevin --- drivers/staging/greybus/audio_module.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c index c52c4f3..a243d60 100644 --- a/drivers/staging/greybus/audio_module.c +++ b/drivers/staging/greybus/audio_module.c @@ -175,8 +175,8 @@ static int gbaudio_codec_request_handler(struct gb_operation *op) } static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) + struct greybus_descriptor_cport *cport_desc, + struct gb_bundle *bundle) { struct gb_connection *connection; @@ -199,8 +199,8 @@ static int gb_audio_add_mgmt_connection(struct gbaudio_module_info *gbmodule, } static int gb_audio_add_data_connection(struct gbaudio_module_info *gbmodule, - struct greybus_descriptor_cport *cport_desc, - struct gb_bundle *bundle) + struct greybus_descriptor_cport *cport_desc, + struct gb_bundle *bundle) { struct gb_connection *connection; struct gbaudio_data_connection *dai; -- 2.7.4 From digetx at gmail.com Thu Nov 12 22:37:01 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 13 Nov 2020 01:37:01 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201112200123.GF4742@sirena.org.uk> References: <20201104234427.26477-1-digetx@gmail.com> <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> Message-ID: 12.11.2020 23:01, Mark Brown ?????: >> But it's not allowed to change voltage of a dummy regulator, is it >> intentional? > Of course not, we can't know if the requested new voltage is valid - the > driver would have to have explict support for handling situations where > it's not possible to change the voltage (which it can detect through > enumerating the values it wants to set at startup). > > [Requesting the same supply multiple times] But how driver is supposed to recognize that it's a dummy or buggy regulator if it rejects all voltages? From gch981213 at gmail.com Fri Nov 13 00:40:09 2020 From: gch981213 at gmail.com (Chuanhong Guo) Date: Fri, 13 Nov 2020 08:40:09 +0800 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: On Thu, Nov 12, 2020 at 1:23 PM Sergio Paracuellos wrote: > > To avoid weird behaviour because of some drivers are > not using properly clocks we have the CLK_IGNORED_UNUSED, which as you > can see is currently being used in my code. Using that all seems to > work as expected as it is now. The whole point of having a clock gate driver is to gate unused clocks to save (maybe a tiny bit of) power. It's other peripheral drivers' fault that it doesn't enable clocks properly and we shouldn't just work-around the problem in the clock driver by disallowing auto clock gating. -- Regards, Chuanhong Guo From sergio.paracuellos at gmail.com Fri Nov 13 05:32:55 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 06:32:55 +0100 Subject: [PATCH 0/7] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 In-Reply-To: References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> Message-ID: On Fri, Nov 13, 2020 at 1:40 AM Chuanhong Guo wrote: > > On Thu, Nov 12, 2020 at 1:23 PM Sergio Paracuellos > wrote: > > > > To avoid weird behaviour because of some drivers are > > not using properly clocks we have the CLK_IGNORED_UNUSED, which as you > > can see is currently being used in my code. Using that all seems to > > work as expected as it is now. > > The whole point of having a clock gate driver is to gate unused > clocks to save (maybe a tiny bit of) power. It's other peripheral > drivers' fault that it doesn't enable clocks properly and we shouldn't > just work-around the problem in the clock driver by disallowing auto > clock gating. > Totally agreed with what you are saying here but I don't really think using the flag is a workaround. It is just a way to ensure no regressions occurred until all drivers are adapted and also having all of them enabled is the behaviour. For me adapt the rest of driver code should be a different patch set after this driver is properly finished and mainlined. > -- > Regards, > Chuanhong Guo Best regards, Sergio Paracuellos From dmitry.torokhov at gmail.com Fri Nov 13 07:26:15 2020 From: dmitry.torokhov at gmail.com (Dmitry Torokhov) Date: Thu, 12 Nov 2020 23:26:15 -0800 Subject: [PATCH v4 01/11] firmware: raspberrypi: Keep count of all consumers In-Reply-To: References: <20201112163630.17177-1-nsaenzjulienne@suse.de> <20201112163630.17177-2-nsaenzjulienne@suse.de> Message-ID: <20201113072615.GE356503@dtor-ws> On Thu, Nov 12, 2020 at 07:52:14PM +0200, Andy Shevchenko wrote: > On Thu, Nov 12, 2020 at 6:40 PM Nicolas Saenz Julienne > wrote: > > > > When unbinding the firmware device we need to make sure it has no > > consumers left. Otherwise we'd leave them with a firmware handle > > pointing at freed memory. > > > > Keep a reference count of all consumers and introduce rpi_firmware_put() > > which will permit automatically decrease the reference count upon > > unbinding consumer drivers. > > ... > > > /** > > - * rpi_firmware_get - Get pointer to rpi_firmware structure. > > * @firmware_node: Pointer to the firmware Device Tree node. > > * > > + * The reference to rpi_firmware has to be released with rpi_firmware_put(). > > + * > > * Returns NULL is the firmware device is not ready. > > */ > > struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) > > { > > struct platform_device *pdev = of_find_device_by_node(firmware_node); > > + struct rpi_firmware *fw; > > > > if (!pdev) > > return NULL; > > > > - return platform_get_drvdata(pdev); > > + fw = platform_get_drvdata(pdev); > > + if (!fw) > > + return NULL; > > + > > + if (!kref_get_unless_zero(&fw->consumers)) > > + return NULL; > > Don't we have a more traditional way of doing this, i.e. > try_module_get() coupled with get_device() ? get_device() will make sure that device is there, but gives no assurances that device is bound to a driver, so it will not help with the racy access to firmware via platform_get_drvdata() call. Thanks. -- Dmitry From info at kshamadevigroup.com Fri Nov 13 04:43:58 2020 From: info at kshamadevigroup.com (Home of Mega Millions and Powerball) Date: Thu, 12 Nov 2020 20:43:58 -0800 Subject: Home of Mega Millions and Powerball Message-ID: <20201113073043.E369487852@hemlock.osuosl.org> Dear Email Owner, Congratulation! Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. This Electronic E-mail notification is to remind you again that your email address has won you the sum of nine hundred and fifty thousand dollars ($950.000.00) from the ($165.000.000.00) Online MEGA MILLIONS POWERBALL LOTTERY. Email addresses were randomly collected from various region and domins and your email won the lucky number 23-45-53-58-62 + 13 in the Mega Million Powerball Lottery. In other to access the winning amount kindly contact our fudiciary agent for your online Payment Identification Number (Pin) that will enable you transfer your payment to your prefer bank account with your reference number: Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. Please quote your reference when contacting our Payment Agents. Blutter Bros. E-mail: contact at itpm-safi.ac.ma Congratulations. USA-UK Home of Mega Millions and Powerball, the USA's biggest multi-state lottery games. BZMSLBKQPLLMYDUBZQTWWKELHGMUUQEXXBIDEL From info at kshamadevigroup.com Fri Nov 13 04:43:58 2020 From: info at kshamadevigroup.com (Home of Mega Millions and Powerball) Date: Thu, 12 Nov 2020 20:43:58 -0800 Subject: Home of Mega Millions and Powerball Message-ID: <20201113073044.7613B873EA@whitealder.osuosl.org> Dear Email Owner, Congratulation! Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. This Electronic E-mail notification is to remind you again that your email address has won you the sum of nine hundred and fifty thousand dollars ($950.000.00) from the ($165.000.000.00) Online MEGA MILLIONS POWERBALL LOTTERY. Email addresses were randomly collected from various region and domins and your email won the lucky number 23-45-53-58-62 + 13 in the Mega Million Powerball Lottery. In other to access the winning amount kindly contact our fudiciary agent for your online Payment Identification Number (Pin) that will enable you transfer your payment to your prefer bank account with your reference number: Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. Please quote your reference when contacting our Payment Agents. Blutter Bros. E-mail: contact at itpm-safi.ac.ma Congratulations. USA-UK Home of Mega Millions and Powerball, the USA's biggest multi-state lottery games. BZMSLBKQPLLMYDUBZQTWWKELHGMUUQEXXBIDEL From sergio.paracuellos at gmail.com Fri Nov 13 09:10:41 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:41 +0100 Subject: [PATCH v2 0/5] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 Message-ID: <20201113091046.30964-1-sergio.paracuellos@gmail.com> This patchset ports CPU clock detection for MT7621 from OpenWrt and adds a complete clock plan for the mt7621 SOC. The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS (AHB?). * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. No documentation about a probably existant set of dividers for each ip core is included in the datasheets. So we cannot make anything better, AFAICT. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: - "hsdma": "150m" - "fe": "250m" - "sp_divtx": "270m" - "timer": "50m" - "pcm": "270m" - "pio": "50m" - "gdma": "bus" - "nand": "125m" - "i2c": "50m" - "i2s": "270m" - "spi": "bus" - "uart1": "50m" - "uart2": "50m" - "uart3": "50m" - "eth": "50m" - "pcie0": "125m" - "pcie1": "125m" - "pcie2": "125m" - "crypto": "250m" - "shxc": "50m" There was a previous attempt of doing this here[0] but the author (Chuanhong Guo) did not wanted to make assumptions of a clock plan for the platform that time. It seems that now he has a better idea of how the clocks are dispossed for this SoC so he share code[1] where some frequencies and clock parents for the gates are coded from a real mediatek private clock plan. I do really want this to be upstreamed so according to the comments in previous attempt[0] from Oleksij Rempel and the frequencies in code[1] I have tried to do this by myself. All of this patches have been tested in a GNUBee PC1 resulting in a working platform. Changes in v2: - Remove the following patches: * dt: bindings: add mt7621-pll device tree binding documentation. * MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621. - Move all relevant clock code to 'drivers/clk/ralink/clk-mt7621.c' and unify there previous 'mt7621-pll' and 'mt7621-clk' into a unique driver and binding 'mt7621-clk'. - Driver is not a platform driver anymore and now make use of 'CLK_OF_DECLARE' because we need clocks available in 'plat_time_init' before setting up the timer for the GIC. - Use new fixed clocks as parents for different gates and deriving from 'xtal' using frequencies in[1]. - Adapt dts file and bindings header and documentation for new changes. - Change MAINTAINERS file to only contains clk-mt7621.c code and mediatek,mt7621-clk.yaml file. [0]: https://www.lkml.org/lkml/2019/7/23/1044 [1]: https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 Sergio Paracuellos (5): dt-bindings: clock: add dt binding header for mt7621 clocks dt: bindings: add mt7621-clk device tree binding documentation clk: ralink: add clock driver for mt7621 SoC staging: mt7621-dts: make use of new 'mt7621-clk' MAINTAINERS: add MT7621 CLOCK maintainer .../bindings/clock/mediatek,mt7621-clk.yaml | 61 ++++ MAINTAINERS | 6 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 + drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 345 ++++++++++++++++++ drivers/staging/mt7621-dts/gbpc1.dts | 11 - drivers/staging/mt7621-dts/mt7621.dtsi | 72 ++-- include/dt-bindings/clock/mt7621-clk.h | 41 +++ 10 files changed, 504 insertions(+), 50 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 09:10:42 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:42 +0100 Subject: [PATCH v2 1/5] dt-bindings: clock: add dt binding header for mt7621 clocks In-Reply-To: <20201113091046.30964-1-sergio.paracuellos@gmail.com> References: <20201113091046.30964-1-sergio.paracuellos@gmail.com> Message-ID: <20201113091046.30964-2-sergio.paracuellos@gmail.com> Adds dt binding header for 'mediatek,mt7621-clk' clocks. Signed-off-by: Sergio Paracuellos --- include/dt-bindings/clock/mt7621-clk.h | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/dt-bindings/clock/mt7621-clk.h diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 000000000000..1422badcf9de --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Author: Sergio Paracuellos + */ + +#ifndef _DT_BINDINGS_CLK_MT7621_H +#define _DT_BINDINGS_CLK_MT7621_H + +#define MT7621_CLK_XTAL 0 +#define MT7621_CLK_CPU 1 +#define MT7621_CLK_BUS 2 +#define MT7621_CLK_50M 3 +#define MT7621_CLK_125M 4 +#define MT7621_CLK_150M 5 +#define MT7621_CLK_250M 6 +#define MT7621_CLK_270M 7 + +#define MT7621_CLK_HSDMA 8 +#define MT7621_CLK_FE 9 +#define MT7621_CLK_SP_DIVTX 10 +#define MT7621_CLK_TIMER 11 +#define MT7621_CLK_PCM 12 +#define MT7621_CLK_PIO 13 +#define MT7621_CLK_GDMA 14 +#define MT7621_CLK_NAND 15 +#define MT7621_CLK_I2C 16 +#define MT7621_CLK_I2S 17 +#define MT7621_CLK_SPI 18 +#define MT7621_CLK_UART1 19 +#define MT7621_CLK_UART2 20 +#define MT7621_CLK_UART3 21 +#define MT7621_CLK_ETH 22 +#define MT7621_CLK_PCIE0 23 +#define MT7621_CLK_PCIE1 24 +#define MT7621_CLK_PCIE2 25 +#define MT7621_CLK_CRYPTO 26 +#define MT7621_CLK_SHXC 27 + +#define MT7621_CLK_MAX 28 + +#endif /* _DT_BINDINGS_CLK_MT7621_H */ -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 09:10:43 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:43 +0100 Subject: [PATCH v2 2/5] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201113091046.30964-1-sergio.paracuellos@gmail.com> References: <20201113091046.30964-1-sergio.paracuellos@gmail.com> Message-ID: <20201113091046.30964-3-sergio.paracuellos@gmail.com> Adds device tree binding documentation for clocks in the MT7621 SOC. Signed-off-by: Sergio Paracuellos --- .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml new file mode 100644 index 000000000000..363bd9880e29 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT7621 Clock Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +description: | + The MT7621 has a PLL controller from where the cpu clock is provided + as well as derived clocks for the bus and the peripherals. It also + can gate SoC device clocks. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in: + [1]: . + +properties: + compatible: + const: mediatek,mt7621-clk + + ralink,sysctl: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the syscon which is in the same address area with syscon + device. + + "#clock-cells": + description: + The first cell indicates the clock gate number, see [1] for available + clocks. + const: 1 + + clock-output-names: + maxItems: 8 + +required: + - compatible + - ralink,sysctl + - '#clock-cells' + - clock-output-names + +additionalProperties: false + +examples: + - | + #include + + pll { + compatible = "mediatek,mt7621-clk"; + ralink,sysctl = <&sysc>; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "225m", "250m"; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 09:10:45 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:45 +0100 Subject: [PATCH v2 4/5] staging: mt7621-dts: make use of new 'mt7621-clk' In-Reply-To: <20201113091046.30964-1-sergio.paracuellos@gmail.com> References: <20201113091046.30964-1-sergio.paracuellos@gmail.com> Message-ID: <20201113091046.30964-5-sergio.paracuellos@gmail.com> Clocks for SoC mt7621 have been properly integrated so there is no need to declare fixed clocks at all in the device tree. Remove all of them, add new device tree nodes for mt7621-clk and update the rest of the nodes to use them. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-dts/gbpc1.dts | 11 ---- drivers/staging/mt7621-dts/mt7621.dtsi | 72 ++++++++++++-------------- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index a7c0d3115d72..7716d0efe524 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -100,17 +100,6 @@ partition at 50000 { }; }; -&sysclock { - compatible = "fixed-clock"; - /* This is normally 1/4 of cpuclock */ - clock-frequency = <225000000>; -}; - -&cpuclock { - compatible = "fixed-clock"; - clock-frequency = <900000000>; -}; - &pcie { pinctrl-names = "default"; pinctrl-0 = <&pcie_pins>; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 82aa93634eda..f64e66de4bf7 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -1,5 +1,6 @@ #include #include +#include / { #address-cells = <1>; @@ -27,26 +28,13 @@ aliases { serial0 = &uartlite; }; - cpuclock: cpuclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* FIXME: there should be way to detect this */ - clock-frequency = <880000000>; - }; - - sysclock: sysclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* This is normally 1/4 of cpuclock */ - clock-frequency = <220000000>; - }; - - mmc_clock: mmc_clock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; + pll: pll { + compatible = "mediatek,mt7621-clk"; + ralink,sysctl = <&sysc>; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "225m", "250m"; }; mmc_fixed_3v3: fixedregulator at 0 { @@ -76,7 +64,7 @@ palmbus: palmbus at 1E000000 { #size-cells = <1>; sysc: sysc at 0 { - compatible = "mtk,mt7621-sysc"; + compatible = "mtk,mt7621-sysc", "syscon"; reg = <0x0 0x100>; }; @@ -100,8 +88,8 @@ i2c: i2c at 900 { compatible = "mediatek,mt7621-i2c"; reg = <0x900 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2C>; + clock-names = "i2c"; resets = <&rstctrl 16>; reset-names = "i2c"; @@ -118,8 +106,8 @@ i2s: i2s at a00 { compatible = "mediatek,mt7621-i2s"; reg = <0xa00 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2S>; + clock-names = "i2s"; resets = <&rstctrl 17>; reset-names = "i2s"; @@ -155,8 +143,8 @@ uartlite: uartlite at c00 { compatible = "ns16550a"; reg = <0xc00 0x100>; - clocks = <&sysclock>; - clock-frequency = <50000000>; + clocks = <&pll MT7621_CLK_UART1>; + clock-names = "uart1"; interrupt-parent = <&gic>; interrupts = ; @@ -172,7 +160,7 @@ spi0: spi at b00 { compatible = "ralink,mt7621-spi"; reg = <0xb00 0x100>; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_SPI>; resets = <&rstctrl 18>; reset-names = "spi"; @@ -188,6 +176,8 @@ gdma: gdma at 2800 { compatible = "ralink,rt3883-gdma"; reg = <0x2800 0x800>; + clocks = <&pll MT7621_CLK_GDMA>; + clock-names = "gdma"; resets = <&rstctrl 14>; reset-names = "dma"; @@ -205,6 +195,8 @@ hsdma: hsdma at 7000 { compatible = "mediatek,mt7621-hsdma"; reg = <0x7000 0x1000>; + clocks = <&pll MT7621_CLK_HSDMA>; + clock-names = "hsdma"; resets = <&rstctrl 5>; reset-names = "hsdma"; @@ -315,11 +307,6 @@ rstctrl: rstctrl { #reset-cells = <1>; }; - clkctrl: clkctrl { - compatible = "ralink,rt2880-clock"; - #clock-cells = <1>; - }; - sdhci: sdhci at 1E130000 { status = "disabled"; @@ -338,7 +325,8 @@ sdhci: sdhci at 1E130000 { pinctrl-0 = <&sdhci_pins>; pinctrl-1 = <&sdhci_pins>; - clocks = <&mmc_clock &mmc_clock>; + clocks = <&pll MT7621_CLK_SHXC>, + <&pll MT7621_CLK_50M>; clock-names = "source", "hclk"; interrupt-parent = <&gic>; @@ -353,7 +341,7 @@ xhci: xhci at 1E1C0000 { 0x1e1d0700 0x0100>; reg-names = "mac", "ippc"; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_XTAL>; clock-names = "sys_ck"; interrupt-parent = <&gic>; @@ -372,7 +360,7 @@ gic: interrupt-controller at 1fbc0000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&cpuclock>; + clocks = <&pll MT7621_CLK_CPU>; }; }; @@ -385,6 +373,9 @@ nand: nand at 1e003000 { 0x1e003800 0x800>; #address-cells = <1>; #size-cells = <1>; + + clocks = <&pll MT7621_CLK_NAND>; + clock-names = "nand"; }; ethsys: syscon at 1e000000 { @@ -398,8 +389,9 @@ ethernet: ethernet at 1e100000 { compatible = "mediatek,mt7621-eth"; reg = <0x1e100000 0x10000>; - clocks = <&sysclock>; - clock-names = "ethif"; + clocks = <&pll MT7621_CLK_FE>, + <&pll MT7621_CLK_ETH>; + clock-names = "fe", "ethif"; #address-cells = <1>; #size-cells = <0>; @@ -532,7 +524,9 @@ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; reset-names = "pcie0", "pcie1", "pcie2"; - clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; + clocks = <&pll MT7621_CLK_PCIE0>, + <&pll MT7621_CLK_PCIE1>, + <&pll MT7621_CLK_PCIE2>; clock-names = "pcie0", "pcie1", "pcie2"; phys = <&pcie0_phy 1>, <&pcie2_phy 0>; phy-names = "pcie-phy0", "pcie-phy2"; -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 09:10:46 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:46 +0100 Subject: [PATCH v2 5/5] MAINTAINERS: add MT7621 CLOCK maintainer In-Reply-To: <20201113091046.30964-1-sergio.paracuellos@gmail.com> References: <20201113091046.30964-1-sergio.paracuellos@gmail.com> Message-ID: <20201113091046.30964-6-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 clock driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f1f088a29bc2..30822ad6837c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11142,6 +11142,12 @@ L: linux-wireless at vger.kernel.org S: Maintained F: drivers/net/wireless/mediatek/mt7601u/ +MEDIATEK MT7621 CLOCK DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml +F: drivers/clk/ralink/clk-mt7621.c + MEDIATEK MT7621/28/88 I2C DRIVER M: Stefan Roese L: linux-i2c at vger.kernel.org -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 09:10:44 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 10:10:44 +0100 Subject: [PATCH v2 3/5] clk: ralink: add clock driver for mt7621 SoC In-Reply-To: <20201113091046.30964-1-sergio.paracuellos@gmail.com> References: <20201113091046.30964-1-sergio.paracuellos@gmail.com> Message-ID: <20201113091046.30964-4-sergio.paracuellos@gmail.com> The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS. * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: * "hsdma": "150m" * "fe": "250m" * "sp_divtx": "270m" * "timer": "50m" * "pcm": "270m" * "pio": "50m" * "gdma": "bus" * "nand": "125m" * "i2c": "50m" * "i2s": "270m" * "spi": "bus" * "uart1": "50m" * "uart2": "50m" * "uart3": "50m" * "eth": "50m" * "pcie0": "125m" * "pcie1": "125m" * "pcie2": "125m" * "crypto": "250m" * "shxc": "50m" With this information the clk driver will provide clock and gates functionality from a a set of hardcoded clocks allowing to define a nice device tree without fixed clocks. Signed-off-by: Sergio Paracuellos --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 ++ drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 345 ++++++++++++++++++++++++++++++++ 5 files changed, 363 insertions(+) create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..5f94c4329033 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -372,6 +372,7 @@ source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" +source "drivers/clk/ralink/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..6578e167b047 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-y += ralink/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ diff --git a/drivers/clk/ralink/Kconfig b/drivers/clk/ralink/Kconfig new file mode 100644 index 000000000000..7e8697327e0c --- /dev/null +++ b/drivers/clk/ralink/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# MediaTek Mt7621 Clock Driver +# +menu "Clock driver for mediatek mt7621 SoC" + depends on SOC_MT7621 || COMPILE_TEST + +config CLK_MT7621 + bool "Clock driver for MediaTek MT7621" + depends on SOC_MT7621 || COMPILE_TEST + default SOC_MT7621 + help + This driver supports MediaTek MT7621 basic clocks. +endmenu diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile new file mode 100644 index 000000000000..cf6f9216379d --- /dev/null +++ b/drivers/clk/ralink/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_MT7621) += clk-mt7621.o diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c new file mode 100644 index 000000000000..03ad27048053 --- /dev/null +++ b/drivers/clk/ralink/clk-mt7621.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mediatek MT7621 Clock Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configuration registers */ +#define SYSC_REG_SYSTEM_CONFIG0 0x10 +#define SYSC_REG_SYSTEM_CONFIG1 0x14 +#define SYSC_REG_CLKCFG0 0x2c +#define SYSC_REG_CLKCFG1 0x30 +#define SYSC_REG_CUR_CLK_STS 0x44 + +#define MEMC_REG_CPU_PLL 0x648 +#define XTAL_MODE_SEL_MASK 0x7 +#define XTAL_MODE_SEL_SHIFT 6 + +#define CPU_CLK_SEL_MASK 0x3 +#define CPU_CLK_SEL_SHIFT 30 + +#define CUR_CPU_FDIV_MASK 0x1f +#define CUR_CPU_FDIV_SHIFT 8 +#define CUR_CPU_FFRAC_MASK 0x1f +#define CUR_CPU_FFRAC_SHIFT 0 + +#define CPU_PLL_PREDIV_MASK 0x3 +#define CPU_PLL_PREDIV_SHIFT 12 +#define CPU_PLL_FBDIV_MASK 0x7f +#define CPU_PLL_FBDIV_SHIFT 4 + +#define MHZ(x) ((x) * 1000 * 1000) + +struct mt7621_clk_provider { + struct device_node *node; + struct regmap *syscon_regmap; + struct clk_hw_onecell_data *clk_data; +}; + +struct mt7621_clk { + struct mt7621_clk_provider *clk_prov; + struct clk_hw hw; +}; + +struct mt7621_fixed_clk { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + unsigned long rate; + struct clk_hw *hw; +}; + +struct mt7621_gate { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + u32 bit_idx; + struct clk_hw hw; +}; + +#define GATE(_id, _name, _pname, _shift) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .bit_idx = _shift \ + } + +static struct mt7621_gate mt7621_gates[] = { + GATE(MT7621_CLK_HSDMA, "hsdma", "150m", BIT(5)), + GATE(MT7621_CLK_FE, "fe", "250m", BIT(6)), + GATE(MT7621_CLK_SP_DIVTX, "sp_divtx", "270m", BIT(7)), + GATE(MT7621_CLK_TIMER, "timer", "50m", BIT(8)), + GATE(MT7621_CLK_PCM, "pcm", "270m", BIT(11)), + GATE(MT7621_CLK_PIO, "pio", "50m", BIT(13)), + GATE(MT7621_CLK_GDMA, "gdma", "bus", BIT(14)), + GATE(MT7621_CLK_NAND, "nand", "125m", BIT(15)), + GATE(MT7621_CLK_I2C, "i2c", "50m", BIT(16)), + GATE(MT7621_CLK_I2S, "i2s", "270m", BIT(17)), + GATE(MT7621_CLK_SPI, "spi", "bus", BIT(18)), + GATE(MT7621_CLK_UART1, "uart1", "50m", BIT(19)), + GATE(MT7621_CLK_UART2, "uart2", "50m", BIT(20)), + GATE(MT7621_CLK_UART3, "uart3", "50m", BIT(21)), + GATE(MT7621_CLK_ETH, "eth", "50m", BIT(23)), + GATE(MT7621_CLK_PCIE0, "pcie0", "125m", BIT(24)), + GATE(MT7621_CLK_PCIE1, "pcie1", "125m", BIT(25)), + GATE(MT7621_CLK_PCIE2, "pcie2", "125m", BIT(26)), + GATE(MT7621_CLK_CRYPTO, "crypto", "250m", BIT(29)), + GATE(MT7621_CLK_SHXC, "shxc", "50m", BIT(30)) +}; + +static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_gate, hw); +} + +static int mt7621_gate_enable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + return regmap_update_bits(scon, SYSC_REG_CLKCFG1, + clk_gate->bit_idx, clk_gate->bit_idx); +} + +static void mt7621_gate_disable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + regmap_update_bits(scon, SYSC_REG_CLKCFG1, clk_gate->bit_idx, 0); +} + +static int mt7621_gate_is_enabled(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + unsigned int val; + + if (regmap_read(scon, SYSC_REG_CLKCFG1, &val)) + return 0; + + return val & clk_gate->bit_idx; +} + +static const struct clk_ops mt7621_gate_ops = { + .enable = mt7621_gate_enable, + .disable = mt7621_gate_disable, + .is_enabled = mt7621_gate_is_enabled, +}; + +static void mt7621_gate_ops_init(struct device_node *np, + struct mt7621_gate *sclk) +{ + struct clk_init_data init = { + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .num_parents = 1, + .parent_names = &sclk->parent_name, + .ops = &mt7621_gate_ops, + .name = sclk->name, + }; + + sclk->hw.init = &init; + of_clk_hw_register(np, &sclk->hw); +} + +static void mt7621_register_gates(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int i; + + for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + sclk->clk_prov = clk_prov; + mt7621_gate_ops_init(clk_prov->node, sclk); + hws[sclk->idx] = &sclk->hw; + (*clk_data)->num++; + } +} + +#define FIXED(_id, _name, _pname, _rate) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .rate = _rate \ + } + +static struct mt7621_fixed_clk mt7621_fixed_clks[] = { + FIXED(MT7621_CLK_50M, "50m", "xtal", MHZ(50)), + FIXED(MT7621_CLK_125M, "125m", "xtal", MHZ(125)), + FIXED(MT7621_CLK_150M, "150m", "xtal", MHZ(150)), + FIXED(MT7621_CLK_250M, "250m", "xtal", MHZ(250)), + FIXED(MT7621_CLK_270M, "270m", "xtal", MHZ(270)), +}; + +static void mt7621_register_fixed_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int i; + + for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + sclk->clk_prov = clk_prov; + sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name, + sclk->parent_name, 0, + sclk->rate); + hws[sclk->idx] = sclk->hw; + (*clk_data)->num++; + } +} + +static inline struct mt7621_clk *to_mt7621_clk(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_clk, hw); +} + +static unsigned long mt7621_xtal_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 val; + + regmap_read(scon, SYSC_REG_SYSTEM_CONFIG0, &val); + val = (val >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; + + if (val <= 2) + return MHZ(20); + else if (val <= 5) + return MHZ(40); + + return MHZ(25); +} + +static unsigned long mt7621_cpu_recalc_rate(struct clk_hw *hw, + unsigned long xtal_clk) +{ + static const u32 prediv_tbl[] = { 0, 1, 2, 2 }; + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 clkcfg, clk_sel, curclk, ffiv, ffrac; + u32 pll, prediv, fbdiv; + unsigned long cpu_clk; + + regmap_read(scon, SYSC_REG_CLKCFG0, &clkcfg); + clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK; + + regmap_read(scon, SYSC_REG_CUR_CLK_STS, &curclk); + ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK; + ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK; + + switch (clk_sel) { + case 0: + cpu_clk = MHZ(500); + break; + case 1: + pll = rt_memc_r32(MEMC_REG_CPU_PLL); + fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK; + prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK; + cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; + break; + default: + cpu_clk = xtal_clk; + } + + return cpu_clk / ffiv * ffrac; +} + +static unsigned long mt7621_bus_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate / 4; +} + +#define CLK_BASE(_name, _parent, _recalc) { \ + .init = &(struct clk_init_data) { \ + .name = _name, \ + .ops = &(const struct clk_ops) { \ + .recalc_rate = _recalc, \ + }, \ + .parent_names = (const char *const[]) { _parent }, \ + .num_parents = _parent ? 1 : 0 \ + }, \ +} + +static struct mt7621_clk mt7621_clks_base[] = { + { NULL, CLK_BASE("xtal", NULL, mt7621_xtal_recalc_rate) }, + { NULL, CLK_BASE("cpu", "xtal", mt7621_cpu_recalc_rate) }, + { NULL, CLK_BASE("bus", "cpu", mt7621_bus_recalc_rate) }, +}; + +static void mt7621_register_top_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int i; + + for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + sclk->clk_prov = clk_prov; + of_clk_hw_register(clk_prov->node, &sclk->hw); + hws[i] = &sclk->hw; + (*clk_data)->num++; + } +} + +static void __init mt7621_clk_init(struct device_node *node) +{ + struct mt7621_clk_provider *clk_prov; + struct clk_hw_onecell_data **clk_data; + int count; + + clk_prov = kzalloc(sizeof(*clk_prov), GFP_KERNEL); + if (!clk_prov) + return; + + clk_prov->syscon_regmap = syscon_regmap_lookup_by_phandle(node, "ralink,sysctl"); + if (IS_ERR(clk_prov->syscon_regmap)) { + pr_err("Could not get syscon regmap\n"); + goto free_clk_prov; + } + + clk_prov->node = node; + + clk_data = &clk_prov->clk_data; + count = ARRAY_SIZE(mt7621_clks_base) + ARRAY_SIZE(mt7621_gates); + *clk_data = kzalloc(struct_size(*clk_data, hws, count), GFP_KERNEL); + if (!*clk_data) + goto free_clk_prov; + + mt7621_register_top_clocks(clk_prov); + mt7621_register_fixed_clocks(clk_prov); + mt7621_register_gates(clk_prov); + + of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_prov->clk_data); + + return; + +free_clk_prov: + kfree(clk_prov); +} + +CLK_OF_DECLARE(mt7621_clk, "mediatek,mt7621-clk", mt7621_clk_init); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("Mediatek Mt7621 clock driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From nsaenzjulienne at suse.de Fri Nov 13 09:21:28 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Fri, 13 Nov 2020 10:21:28 +0100 Subject: [PATCH v4 02/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: References: <20201112163630.17177-1-nsaenzjulienne@suse.de> <20201112163630.17177-3-nsaenzjulienne@suse.de> Message-ID: <3af26701a12b0bcb55b8d422e2a18f06a8e94d4d.camel@suse.de> On Thu, 2020-11-12 at 18:25 +0100, Bartosz Golaszewski wrote: > On Thu, Nov 12, 2020 at 5:44 PM Nicolas Saenz Julienne > wrote: > > Itroduce devm_rpi_firmware_get(), it'll simplify the firmware handling > > for most consumers. > > > > Suggested-by: Bartosz Golaszewski > > Signed-off-by: Nicolas Saenz Julienne > > --- > > > > Changes since v2: > > - Introduce devm_rpi_firmware_get() > > > > drivers/firmware/raspberrypi.c | 31 +++++++++++++++++++++- > > include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++ > > 2 files changed, 38 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c > > index 438e17074a97..4ab2dfdc82ad 100644 > > --- a/drivers/firmware/raspberrypi.c > > +++ b/drivers/firmware/raspberrypi.c > > @@ -237,10 +237,17 @@ static void rpi_firmware_delete(struct kref *kref) > > kfree(fw); > > } > > > > -void rpi_firmware_put(struct rpi_firmware *fw) > > +static void __rpi_firmware_put(void *data) > > { > > The '__' prefix is very vague and usually used for unlocked variants > of functions. The casting to void * in rpi_firmware_put() is also > unneeded. I would much prefer that the devres release callback be > called devm_rpi_firmware_put() and that it call rpi_firmware_put() > which would then call kref_put(). Yes, that's better. I'll change it. Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From broonie at kernel.org Fri Nov 13 14:29:37 2020 From: broonie at kernel.org (Mark Brown) Date: Fri, 13 Nov 2020 14:29:37 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: References: <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> Message-ID: <20201113142937.GB4828@sirena.org.uk> On Fri, Nov 13, 2020 at 01:37:01AM +0300, Dmitry Osipenko wrote: > 12.11.2020 23:01, Mark Brown ?????: > >> But it's not allowed to change voltage of a dummy regulator, is it > >> intentional? > > Of course not, we can't know if the requested new voltage is valid - the > > driver would have to have explict support for handling situations where > > it's not possible to change the voltage (which it can detect through > > enumerating the values it wants to set at startup). > > [Requesting the same supply multiple times] > But how driver is supposed to recognize that it's a dummy or buggy > regulator if it rejects all voltages? It's not clear if it matters - it's more a policy decision on the part of the driver about what it thinks safe error handling is. If it's not possible to read voltages from the regulator the consumer driver has to decide what it thinks it's safe for it to do, either way it has no idea what the actual current voltage is. It could assume that it's something that supports all the use cases it wants to use and just carry on with no configuration of voltages, it could decide that it might not support everything and not make any changes to be safe, or do something like try to figure out that if we're currently at a given OPP that's the top OPP possible. Historically when we've not had regulator control in these drivers so they have effectively gone with the first option of just assuming it's a generally safe value, this often aligns with what the power on requirements for SoCs are so it's not unreasonable. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From ulf.hansson at linaro.org Fri Nov 13 14:45:43 2020 From: ulf.hansson at linaro.org (Ulf Hansson) Date: Fri, 13 Nov 2020 15:45:43 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> <20201112204358.GA1027187@ulmo> <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> Message-ID: On Thu, 12 Nov 2020 at 23:14, Dmitry Osipenko wrote: > > 12.11.2020 23:43, Thierry Reding ?????: > >> The difference in comparison to using voltage regulator directly is > >> minimal, basically the core-supply phandle is replaced is replaced with > >> a power-domain phandle in a device tree. > > These new power-domain handles would have to be added to devices that > > potentially already have a power-domain handle, right? Isn't that going > > to cause issues? I vaguely recall that we already have multiple power > > domains for the XUSB controller and we have to jump through extra hoops > > to make that work. > > I modeled the core PD as a parent of the PMC sub-domains, which > presumably is a correct way to represent the domains topology. > > https://gist.github.com/digetx/dfd92c7f7e0aa6cef20403c4298088d7 That could make sense, it seems. Anyway, this made me realize that dev_pm_genpd_set_performance_state(dev) returns -EINVAL, in case the device's genpd doesn't have the ->set_performance_state() assigned. This may not be correct. Instead we should likely consider an empty callback as okay and continue to walk the topology upwards to the parent domain, etc. Just wanted to point this out. I intend to post a patch as soon as I can for this. [...] Kind regards Uffe From info34 at formacionestatal.es Fri Nov 13 14:47:00 2020 From: info34 at formacionestatal.es (FOESCO) Date: Fri, 13 Nov 2020 15:47:00 +0100 Subject: =?Windows-1252?Q?Formaci=F3n_Bonificable_2020?= Message-ID: <5936408169640122466202@DESKTOP-MFVDD89> Buenos d?as Desde FOESCO os informamos que se encuentra abierto el plazo de inscripci?n para la presente y ?LTIMA CONVOCATORIA 2020 de Cursos Bonificables. Recordamos que los cursos van dirigidos a empleados en activo y en situaci?n de ERTE y son totalmente bonificables con cargo al Cr?dito de Formaci?n 2020. Si vuestra empresa todav?a dispone de Cr?dito de Formaci?n 2020 esta es la ?ltima oportunidad para poder consumirlo. Dese?is que os mandemos la informaci?n? Quedamos a la espera de vuestra respuesta. Saludos cordiales. Alex Pons Director FOESCO. FOESCO Formaci?n Estatal Continua. Entidad Organizadora: B200592AA www.foesco.com e-mail: cursos at foesco.net Tel: 910 323 794 (Horario de 9h a 15h y de 17h a 20h de Lunes a Viernes) FOESCO ofrece formaci?n a empresas y trabajadores en activo a trav?s de cursos bonificados por la Fundaci?n Estatal para la Formaci?n en el Empleo (antiguo FORCEM) que gestiona las acciones formativas de FORMACI?N CONTINUA para trabajadores y se rige por la ley 30/2015 de 9 de Septiembre. Antes de imprimir este e-mail piense bien si es necesario hacerlo. Before printing this e-mail please think twice if you really need it. FOESCO Tfno: 910 382 880 Email: cursos at foesco.com. La informaci?n transmitida en este mensaje est? dirigida solamente a las personas o entidades que figuran en el encabezamiento y contiene informaci?n confidencial, por lo que, si usted lo recibiera por error, por favor destr?yalo sin copiarlo, usarlo ni distribuirlo, comunic?ndolo inmediatamente al emisor del mensaje. De conformidad con lo dispuesto en el Reglamento Europeo del 2016/679, del 27 de Abril de 2016, FOESCO le informa que los datos por usted suministrados ser?n tratados con las medidas de seguridad conformes a la normativa vigente que se requiere. Dichos datos ser?n empleados con fines de gesti?n. Para el ejercicio de sus derechos de transparencia, informaci?n, acceso, rectificaci?n, supresi?n o derecho al olvido, limitaci?n del tratamiento , portabilidad de datos y oposici?n de sus datos de car?cter personal deber? dirigirse a la direcci?n del Responsable del tratamiento a C/ LAGUNA DEL MARQUESADO N?10, 28021, MADRID, "PULSANDO AQUI" y "ENVIAR" o a traves de la direcci?n de correo electr?nico: bajas at foesco.com From sergio.paracuellos at gmail.com Fri Nov 13 15:26:08 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:26:08 +0100 Subject: [PATCH] staging: mt7621-pci: avoid to request pci bus resources In-Reply-To: <20201102202515.19073-1-sergio.paracuellos@gmail.com> References: <20201102202515.19073-1-sergio.paracuellos@gmail.com> Message-ID: Hi Greg, On Mon, Nov 2, 2020 at 9:25 PM Sergio Paracuellos wrote: > > After upgrading kernel to version 5.9.x the driver was not > working anymore showing the following kernel trace: > > ... > mt7621-pci 1e140000.pcie: resource collision: > [mem 0x60000000-0x6fffffff] conflicts with pcie at 1e140000 [mem 0x60000000-0x6fffffff] > ------------[ cut here ]------------ > WARNING: CPU: 2 PID: 73 at kernel/resource.c:1400 > devm_request_resource+0xfc/0x10c > Modules linked in: > CPU: 2 PID: 73 Comm: kworker/2:1 Not tainted 5.9.2 #0 > Workqueue: events deferred_probe_work_func > Stack : 00000000 81590000 807d0a1c 808a0000 8fd49080 > 807d0000 00000009 808ac820 > 00000001 808338d0 7fff0001 800839dc 00000049 > 00000001 8fe51b00 367204ab > 00000000 00000000 807d0a1c 807c0000 00000001 > 80082358 8fe50000 00559000 > 00000000 8fe519f1 ffffffff 00000005 00000000 > 00000001 00000000 807d0000 > 00000009 808ac820 00000001 808338d0 00000001 > 803bf1b0 00000008 81390008 > > Call Trace: > [<8000d018>] show_stack+0x30/0x100 > [<8032e66c>] dump_stack+0xa4/0xd4 > [<8002db1c>] __warn+0xc0/0x134 > [<8002dbec>] warn_slowpath_fmt+0x5c/0xac > [<80033b34>] devm_request_resource+0xfc/0x10c > [<80365ff8>] devm_request_pci_bus_resources+0x58/0xdc > [<8048e13c>] mt7621_pci_probe+0x8dc/0xe48 > [<803d2140>] platform_drv_probe+0x40/0x94 > [<803cfd94>] really_probe+0x108/0x4ec > [<803cd958>] bus_for_each_drv+0x70/0xb0 > [<803d0388>] __device_attach+0xec/0x164 > [<803cec8c>] bus_probe_device+0xa4/0xc0 > [<803cf1c4>] deferred_probe_work_func+0x80/0xc4 > [<80048444>] process_one_work+0x260/0x510 > [<80048a4c>] worker_thread+0x358/0x5cc > [<8004f7d0>] kthread+0x134/0x13c > [<80007478>] ret_from_kernel_thread+0x14/0x1c > ---[ end trace a9dd2e37537510d3 ]--- > mt7621-pci 1e140000.pcie: Error requesting resources > mt7621-pci: probe of 1e140000.pcie failed with error -16 > ... > > With commit 669cbc708122 ("PCI: Move DT resource setup into > devm_pci_alloc_host_bridge()"), the DT 'ranges' is parsed and populated > into resources when the host bridge is allocated. The resources are > requested as well, but that happens a 2nd time for this driver in > mt7621_pcie_request_resources(). Hence we should avoid this second > request. > > Also, the bus ranges was also populated by default, so we can remove > it from mt7621_pcie_request_resources() to avoid the following trace > if we don't avoid it: > > pci_bus 0000:00: busn_res: can not insert [bus 00-ff] > under domain [bus 00-ff] (conflicts with (null) [bus 00-ff]) > > Function 'mt7621_pcie_request_resources' has been renamed into > 'mt7621_pcie_add_resources' which now is a more accurate name > for this function. > > Cc: stable at vger.kernel.org#5.9.x- > Signed-off-by: Sergio Paracuellos This patch have to be added also for stable 5.9.x because driver is broken in all kernel 5.9.x releases. I noticed a new stable release comes three days ago (5.9.8) and this was not added. I was wondering if the way I marked this patch to be included is wrong. Thanks in advance for your time. Best regards, Sergio Paracuellos > --- > drivers/staging/mt7621-pci/pci-mt7621.c | 15 +++------------ > 1 file changed, 3 insertions(+), 12 deletions(-) > > diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c > index f961b353c22e..8831db383fad 100644 > --- a/drivers/staging/mt7621-pci/pci-mt7621.c > +++ b/drivers/staging/mt7621-pci/pci-mt7621.c > @@ -653,16 +653,11 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie) > return 0; > } > > -static int mt7621_pcie_request_resources(struct mt7621_pcie *pcie, > - struct list_head *res) > +static void mt7621_pcie_add_resources(struct mt7621_pcie *pcie, > + struct list_head *res) > { > - struct device *dev = pcie->dev; > - > pci_add_resource_offset(res, &pcie->io, pcie->offset.io); > pci_add_resource_offset(res, &pcie->mem, pcie->offset.mem); > - pci_add_resource(res, &pcie->busn); > - > - return devm_request_pci_bus_resources(dev, res); > } > > static int mt7621_pcie_register_host(struct pci_host_bridge *host, > @@ -738,11 +733,7 @@ static int mt7621_pci_probe(struct platform_device *pdev) > > setup_cm_memory_region(pcie); > > - err = mt7621_pcie_request_resources(pcie, &res); > - if (err) { > - dev_err(dev, "Error requesting resources\n"); > - return err; > - } > + mt7621_pcie_add_resources(pcie, &res); > > err = mt7621_pcie_register_host(bridge, &res); > if (err) { > -- > 2.25.1 > From sergio.paracuellos at gmail.com Fri Nov 13 15:46:27 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:27 +0100 Subject: [PATCH v3 0/5] MIPS: ralink: add CPU clock detection and clock gate driver for MT7621 Message-ID: <20201113154632.24973-1-sergio.paracuellos@gmail.com> This patchset ports CPU clock detection for MT7621 from OpenWrt and adds a complete clock plan for the mt7621 SOC. The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS (AHB?). * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. No documentation about a probably existent set of dividers for each ip core is included in the datasheets. So we cannot make anything better, AFAICT. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: - "hsdma": "150m" - "fe": "250m" - "sp_divtx": "270m" - "timer": "50m" - "pcm": "270m" - "pio": "50m" - "gdma": "bus" - "nand": "125m" - "i2c": "50m" - "i2s": "270m" - "spi": "bus" - "uart1": "50m" - "uart2": "50m" - "uart3": "50m" - "eth": "50m" - "pcie0": "125m" - "pcie1": "125m" - "pcie2": "125m" - "crypto": "250m" - "shxc": "50m" There was a previous attempt of doing this here[0] but the author (Chuanhong Guo) did not wanted to make assumptions of a clock plan for the platform that time. It seems that now he has a better idea of how the clocks are dispossed for this SoC so he share code[1] where some frequencies and clock parents for the gates are coded from a real mediatek private clock plan. I do really want this to be upstreamed so according to the comments in previous attempt[0] from Oleksij Rempel and the frequencies in code[1] I have tried to do this by myself. All of this patches have been tested in a GNUBee PC1 resulting in a working platform. Changes in v3: - Fix compilation warnings reported by kernel test robot because of ignoring return values of 'of_clk_hw_register' in functions 'mt7621_register_top_clocks' and 'mt7621_gate_ops_init'. - Fix dts file and binding documentation 'clock-output-names'. Changes in v2: - Remove the following patches: * dt: bindings: add mt7621-pll device tree binding documentation. * MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621. - Move all relevant clock code to 'drivers/clk/ralink/clk-mt7621.c' and unify there previous 'mt7621-pll' and 'mt7621-clk' into a unique driver and binding 'mt7621-clk'. - Driver is not a platform driver anymore and now make use of 'CLK_OF_DECLARE' because we need clocks available in 'plat_time_init' before setting up the timer for the GIC. - Use new fixed clocks as parents for different gates and deriving from 'xtal' using frequencies in[1]. - Adapt dts file and bindings header and documentation for new changes. - Change MAINTAINERS file to only contains clk-mt7621.c code and mediatek,mt7621-clk.yaml file. [0]: https://www.lkml.org/lkml/2019/7/23/1044 [1]: https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 Sergio Paracuellos (5): dt-bindings: clock: add dt binding header for mt7621 clocks dt: bindings: add mt7621-clk device tree binding documentation clk: ralink: add clock driver for mt7621 SoC staging: mt7621-dts: make use of new 'mt7621-clk' MAINTAINERS: add MT7621 CLOCK maintainer .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++ MAINTAINERS | 6 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 + drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 408 ++++++++++++++++++ drivers/staging/mt7621-dts/gbpc1.dts | 11 - drivers/staging/mt7621-dts/mt7621.dtsi | 72 ++-- include/dt-bindings/clock/mt7621-clk.h | 41 ++ 10 files changed, 567 insertions(+), 50 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 15:46:28 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:28 +0100 Subject: [PATCH v3 1/5] dt-bindings: clock: add dt binding header for mt7621 clocks In-Reply-To: <20201113154632.24973-1-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> Message-ID: <20201113154632.24973-2-sergio.paracuellos@gmail.com> Adds dt binding header for 'mediatek,mt7621-clk' clocks. Signed-off-by: Sergio Paracuellos --- include/dt-bindings/clock/mt7621-clk.h | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/dt-bindings/clock/mt7621-clk.h diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 000000000000..1422badcf9de --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Author: Sergio Paracuellos + */ + +#ifndef _DT_BINDINGS_CLK_MT7621_H +#define _DT_BINDINGS_CLK_MT7621_H + +#define MT7621_CLK_XTAL 0 +#define MT7621_CLK_CPU 1 +#define MT7621_CLK_BUS 2 +#define MT7621_CLK_50M 3 +#define MT7621_CLK_125M 4 +#define MT7621_CLK_150M 5 +#define MT7621_CLK_250M 6 +#define MT7621_CLK_270M 7 + +#define MT7621_CLK_HSDMA 8 +#define MT7621_CLK_FE 9 +#define MT7621_CLK_SP_DIVTX 10 +#define MT7621_CLK_TIMER 11 +#define MT7621_CLK_PCM 12 +#define MT7621_CLK_PIO 13 +#define MT7621_CLK_GDMA 14 +#define MT7621_CLK_NAND 15 +#define MT7621_CLK_I2C 16 +#define MT7621_CLK_I2S 17 +#define MT7621_CLK_SPI 18 +#define MT7621_CLK_UART1 19 +#define MT7621_CLK_UART2 20 +#define MT7621_CLK_UART3 21 +#define MT7621_CLK_ETH 22 +#define MT7621_CLK_PCIE0 23 +#define MT7621_CLK_PCIE1 24 +#define MT7621_CLK_PCIE2 25 +#define MT7621_CLK_CRYPTO 26 +#define MT7621_CLK_SHXC 27 + +#define MT7621_CLK_MAX 28 + +#endif /* _DT_BINDINGS_CLK_MT7621_H */ -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 15:46:31 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:31 +0100 Subject: [PATCH v3 4/5] staging: mt7621-dts: make use of new 'mt7621-clk' In-Reply-To: <20201113154632.24973-1-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> Message-ID: <20201113154632.24973-5-sergio.paracuellos@gmail.com> Clocks for SoC mt7621 have been properly integrated so there is no need to declare fixed clocks at all in the device tree. Remove all of them, add new device tree nodes for mt7621-clk and update the rest of the nodes to use them. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-dts/gbpc1.dts | 11 ---- drivers/staging/mt7621-dts/mt7621.dtsi | 72 ++++++++++++-------------- 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index a7c0d3115d72..7716d0efe524 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -100,17 +100,6 @@ partition at 50000 { }; }; -&sysclock { - compatible = "fixed-clock"; - /* This is normally 1/4 of cpuclock */ - clock-frequency = <225000000>; -}; - -&cpuclock { - compatible = "fixed-clock"; - clock-frequency = <900000000>; -}; - &pcie { pinctrl-names = "default"; pinctrl-0 = <&pcie_pins>; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 82aa93634eda..f64e66de4bf7 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -1,5 +1,6 @@ #include #include +#include / { #address-cells = <1>; @@ -27,26 +28,13 @@ aliases { serial0 = &uartlite; }; - cpuclock: cpuclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* FIXME: there should be way to detect this */ - clock-frequency = <880000000>; - }; - - sysclock: sysclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* This is normally 1/4 of cpuclock */ - clock-frequency = <220000000>; - }; - - mmc_clock: mmc_clock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; + pll: pll { + compatible = "mediatek,mt7621-clk"; + ralink,sysctl = <&sysc>; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "250m", "270m"; }; mmc_fixed_3v3: fixedregulator at 0 { @@ -76,7 +64,7 @@ palmbus: palmbus at 1E000000 { #size-cells = <1>; sysc: sysc at 0 { - compatible = "mtk,mt7621-sysc"; + compatible = "mtk,mt7621-sysc", "syscon"; reg = <0x0 0x100>; }; @@ -100,8 +88,8 @@ i2c: i2c at 900 { compatible = "mediatek,mt7621-i2c"; reg = <0x900 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2C>; + clock-names = "i2c"; resets = <&rstctrl 16>; reset-names = "i2c"; @@ -118,8 +106,8 @@ i2s: i2s at a00 { compatible = "mediatek,mt7621-i2s"; reg = <0xa00 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2S>; + clock-names = "i2s"; resets = <&rstctrl 17>; reset-names = "i2s"; @@ -155,8 +143,8 @@ uartlite: uartlite at c00 { compatible = "ns16550a"; reg = <0xc00 0x100>; - clocks = <&sysclock>; - clock-frequency = <50000000>; + clocks = <&pll MT7621_CLK_UART1>; + clock-names = "uart1"; interrupt-parent = <&gic>; interrupts = ; @@ -172,7 +160,7 @@ spi0: spi at b00 { compatible = "ralink,mt7621-spi"; reg = <0xb00 0x100>; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_SPI>; resets = <&rstctrl 18>; reset-names = "spi"; @@ -188,6 +176,8 @@ gdma: gdma at 2800 { compatible = "ralink,rt3883-gdma"; reg = <0x2800 0x800>; + clocks = <&pll MT7621_CLK_GDMA>; + clock-names = "gdma"; resets = <&rstctrl 14>; reset-names = "dma"; @@ -205,6 +195,8 @@ hsdma: hsdma at 7000 { compatible = "mediatek,mt7621-hsdma"; reg = <0x7000 0x1000>; + clocks = <&pll MT7621_CLK_HSDMA>; + clock-names = "hsdma"; resets = <&rstctrl 5>; reset-names = "hsdma"; @@ -315,11 +307,6 @@ rstctrl: rstctrl { #reset-cells = <1>; }; - clkctrl: clkctrl { - compatible = "ralink,rt2880-clock"; - #clock-cells = <1>; - }; - sdhci: sdhci at 1E130000 { status = "disabled"; @@ -338,7 +325,8 @@ sdhci: sdhci at 1E130000 { pinctrl-0 = <&sdhci_pins>; pinctrl-1 = <&sdhci_pins>; - clocks = <&mmc_clock &mmc_clock>; + clocks = <&pll MT7621_CLK_SHXC>, + <&pll MT7621_CLK_50M>; clock-names = "source", "hclk"; interrupt-parent = <&gic>; @@ -353,7 +341,7 @@ xhci: xhci at 1E1C0000 { 0x1e1d0700 0x0100>; reg-names = "mac", "ippc"; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_XTAL>; clock-names = "sys_ck"; interrupt-parent = <&gic>; @@ -372,7 +360,7 @@ gic: interrupt-controller at 1fbc0000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&cpuclock>; + clocks = <&pll MT7621_CLK_CPU>; }; }; @@ -385,6 +373,9 @@ nand: nand at 1e003000 { 0x1e003800 0x800>; #address-cells = <1>; #size-cells = <1>; + + clocks = <&pll MT7621_CLK_NAND>; + clock-names = "nand"; }; ethsys: syscon at 1e000000 { @@ -398,8 +389,9 @@ ethernet: ethernet at 1e100000 { compatible = "mediatek,mt7621-eth"; reg = <0x1e100000 0x10000>; - clocks = <&sysclock>; - clock-names = "ethif"; + clocks = <&pll MT7621_CLK_FE>, + <&pll MT7621_CLK_ETH>; + clock-names = "fe", "ethif"; #address-cells = <1>; #size-cells = <0>; @@ -532,7 +524,9 @@ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; reset-names = "pcie0", "pcie1", "pcie2"; - clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; + clocks = <&pll MT7621_CLK_PCIE0>, + <&pll MT7621_CLK_PCIE1>, + <&pll MT7621_CLK_PCIE2>; clock-names = "pcie0", "pcie1", "pcie2"; phys = <&pcie0_phy 1>, <&pcie2_phy 0>; phy-names = "pcie-phy0", "pcie-phy2"; -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 15:46:30 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:30 +0100 Subject: [PATCH v3 3/5] clk: ralink: add clock driver for mt7621 SoC In-Reply-To: <20201113154632.24973-1-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> Message-ID: <20201113154632.24973-4-sergio.paracuellos@gmail.com> The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS. * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: * "hsdma": "150m" * "fe": "250m" * "sp_divtx": "270m" * "timer": "50m" * "pcm": "270m" * "pio": "50m" * "gdma": "bus" * "nand": "125m" * "i2c": "50m" * "i2s": "270m" * "spi": "bus" * "uart1": "50m" * "uart2": "50m" * "uart3": "50m" * "eth": "50m" * "pcie0": "125m" * "pcie1": "125m" * "pcie2": "125m" * "crypto": "250m" * "shxc": "50m" With this information the clk driver will provide clock and gates functionality from a a set of hardcoded clocks allowing to define a nice device tree without fixed clocks. Signed-off-by: Sergio Paracuellos --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 ++ drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 408 ++++++++++++++++++++++++++++++++ 5 files changed, 426 insertions(+) create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..5f94c4329033 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -372,6 +372,7 @@ source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" +source "drivers/clk/ralink/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..6578e167b047 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-y += ralink/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ diff --git a/drivers/clk/ralink/Kconfig b/drivers/clk/ralink/Kconfig new file mode 100644 index 000000000000..7e8697327e0c --- /dev/null +++ b/drivers/clk/ralink/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# MediaTek Mt7621 Clock Driver +# +menu "Clock driver for mediatek mt7621 SoC" + depends on SOC_MT7621 || COMPILE_TEST + +config CLK_MT7621 + bool "Clock driver for MediaTek MT7621" + depends on SOC_MT7621 || COMPILE_TEST + default SOC_MT7621 + help + This driver supports MediaTek MT7621 basic clocks. +endmenu diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile new file mode 100644 index 000000000000..cf6f9216379d --- /dev/null +++ b/drivers/clk/ralink/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_MT7621) += clk-mt7621.o diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c new file mode 100644 index 000000000000..733aecffd6a9 --- /dev/null +++ b/drivers/clk/ralink/clk-mt7621.c @@ -0,0 +1,408 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mediatek MT7621 Clock Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configuration registers */ +#define SYSC_REG_SYSTEM_CONFIG0 0x10 +#define SYSC_REG_SYSTEM_CONFIG1 0x14 +#define SYSC_REG_CLKCFG0 0x2c +#define SYSC_REG_CLKCFG1 0x30 +#define SYSC_REG_CUR_CLK_STS 0x44 + +#define MEMC_REG_CPU_PLL 0x648 +#define XTAL_MODE_SEL_MASK 0x7 +#define XTAL_MODE_SEL_SHIFT 6 + +#define CPU_CLK_SEL_MASK 0x3 +#define CPU_CLK_SEL_SHIFT 30 + +#define CUR_CPU_FDIV_MASK 0x1f +#define CUR_CPU_FDIV_SHIFT 8 +#define CUR_CPU_FFRAC_MASK 0x1f +#define CUR_CPU_FFRAC_SHIFT 0 + +#define CPU_PLL_PREDIV_MASK 0x3 +#define CPU_PLL_PREDIV_SHIFT 12 +#define CPU_PLL_FBDIV_MASK 0x7f +#define CPU_PLL_FBDIV_SHIFT 4 + +#define MHZ(x) ((x) * 1000 * 1000) + +struct mt7621_clk_provider { + struct device_node *node; + struct regmap *syscon_regmap; + struct clk_hw_onecell_data *clk_data; +}; + +struct mt7621_clk { + struct mt7621_clk_provider *clk_prov; + struct clk_hw hw; +}; + +struct mt7621_fixed_clk { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + unsigned long rate; + struct clk_hw *hw; +}; + +struct mt7621_gate { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + u32 bit_idx; + struct clk_hw hw; +}; + +#define GATE(_id, _name, _pname, _shift) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .bit_idx = _shift \ + } + +static struct mt7621_gate mt7621_gates[] = { + GATE(MT7621_CLK_HSDMA, "hsdma", "150m", BIT(5)), + GATE(MT7621_CLK_FE, "fe", "250m", BIT(6)), + GATE(MT7621_CLK_SP_DIVTX, "sp_divtx", "270m", BIT(7)), + GATE(MT7621_CLK_TIMER, "timer", "50m", BIT(8)), + GATE(MT7621_CLK_PCM, "pcm", "270m", BIT(11)), + GATE(MT7621_CLK_PIO, "pio", "50m", BIT(13)), + GATE(MT7621_CLK_GDMA, "gdma", "bus", BIT(14)), + GATE(MT7621_CLK_NAND, "nand", "125m", BIT(15)), + GATE(MT7621_CLK_I2C, "i2c", "50m", BIT(16)), + GATE(MT7621_CLK_I2S, "i2s", "270m", BIT(17)), + GATE(MT7621_CLK_SPI, "spi", "bus", BIT(18)), + GATE(MT7621_CLK_UART1, "uart1", "50m", BIT(19)), + GATE(MT7621_CLK_UART2, "uart2", "50m", BIT(20)), + GATE(MT7621_CLK_UART3, "uart3", "50m", BIT(21)), + GATE(MT7621_CLK_ETH, "eth", "50m", BIT(23)), + GATE(MT7621_CLK_PCIE0, "pcie0", "125m", BIT(24)), + GATE(MT7621_CLK_PCIE1, "pcie1", "125m", BIT(25)), + GATE(MT7621_CLK_PCIE2, "pcie2", "125m", BIT(26)), + GATE(MT7621_CLK_CRYPTO, "crypto", "250m", BIT(29)), + GATE(MT7621_CLK_SHXC, "shxc", "50m", BIT(30)) +}; + +static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_gate, hw); +} + +static int mt7621_gate_enable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + return regmap_update_bits(scon, SYSC_REG_CLKCFG1, + clk_gate->bit_idx, clk_gate->bit_idx); +} + +static void mt7621_gate_disable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + regmap_update_bits(scon, SYSC_REG_CLKCFG1, clk_gate->bit_idx, 0); +} + +static int mt7621_gate_is_enabled(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + unsigned int val; + + if (regmap_read(scon, SYSC_REG_CLKCFG1, &val)) + return 0; + + return val & clk_gate->bit_idx; +} + +static const struct clk_ops mt7621_gate_ops = { + .enable = mt7621_gate_enable, + .disable = mt7621_gate_disable, + .is_enabled = mt7621_gate_is_enabled, +}; + +static int mt7621_gate_ops_init(struct device_node *np, + struct mt7621_gate *sclk) +{ + struct clk_init_data init = { + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .num_parents = 1, + .parent_names = &sclk->parent_name, + .ops = &mt7621_gate_ops, + .name = sclk->name, + }; + + sclk->hw.init = &init; + return of_clk_hw_register(np, &sclk->hw); +} + +static int mt7621_register_gates(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + sclk->clk_prov = clk_prov; + ret = mt7621_gate_ops_init(clk_prov->node, sclk); + if (ret) { + pr_err("Couldn't register clock %s\n", sclk->name); + goto err_clk_unreg; + } + + hws[sclk->idx] = &sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + clk_hw_unregister(&sclk->hw); + } + return ret; +} + +#define FIXED(_id, _name, _pname, _rate) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .rate = _rate \ + } + +static struct mt7621_fixed_clk mt7621_fixed_clks[] = { + FIXED(MT7621_CLK_50M, "50m", "xtal", MHZ(50)), + FIXED(MT7621_CLK_125M, "125m", "xtal", MHZ(125)), + FIXED(MT7621_CLK_150M, "150m", "xtal", MHZ(150)), + FIXED(MT7621_CLK_250M, "250m", "xtal", MHZ(250)), + FIXED(MT7621_CLK_270M, "270m", "xtal", MHZ(270)), +}; + +static int mt7621_register_fixed_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + sclk->clk_prov = clk_prov; + sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name, + sclk->parent_name, 0, + sclk->rate); + if (IS_ERR(sclk->hw)) { + pr_err("Couldn't register clock %s\n", sclk->name); + ret = PTR_ERR(sclk->hw); + goto err_clk_unreg; + } + + hws[sclk->idx] = sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + clk_hw_unregister_fixed_rate(sclk->hw); + } + return ret; +} + +static inline struct mt7621_clk *to_mt7621_clk(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_clk, hw); +} + +static unsigned long mt7621_xtal_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 val; + + regmap_read(scon, SYSC_REG_SYSTEM_CONFIG0, &val); + val = (val >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; + + if (val <= 2) + return MHZ(20); + else if (val <= 5) + return MHZ(40); + + return MHZ(25); +} + +static unsigned long mt7621_cpu_recalc_rate(struct clk_hw *hw, + unsigned long xtal_clk) +{ + static const u32 prediv_tbl[] = { 0, 1, 2, 2 }; + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 clkcfg, clk_sel, curclk, ffiv, ffrac; + u32 pll, prediv, fbdiv; + unsigned long cpu_clk; + + regmap_read(scon, SYSC_REG_CLKCFG0, &clkcfg); + clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK; + + regmap_read(scon, SYSC_REG_CUR_CLK_STS, &curclk); + ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK; + ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK; + + switch (clk_sel) { + case 0: + cpu_clk = MHZ(500); + break; + case 1: + pll = rt_memc_r32(MEMC_REG_CPU_PLL); + fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK; + prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK; + cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; + break; + default: + cpu_clk = xtal_clk; + } + + return cpu_clk / ffiv * ffrac; +} + +static unsigned long mt7621_bus_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate / 4; +} + +#define CLK_BASE(_name, _parent, _recalc) { \ + .init = &(struct clk_init_data) { \ + .name = _name, \ + .ops = &(const struct clk_ops) { \ + .recalc_rate = _recalc, \ + }, \ + .parent_names = (const char *const[]) { _parent }, \ + .num_parents = _parent ? 1 : 0 \ + }, \ +} + +static struct mt7621_clk mt7621_clks_base[] = { + { NULL, CLK_BASE("xtal", NULL, mt7621_xtal_recalc_rate) }, + { NULL, CLK_BASE("cpu", "xtal", mt7621_cpu_recalc_rate) }, + { NULL, CLK_BASE("bus", "cpu", mt7621_bus_recalc_rate) }, +}; + +static int mt7621_register_top_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + sclk->clk_prov = clk_prov; + ret = of_clk_hw_register(clk_prov->node, &sclk->hw); + if (ret) { + pr_err("Couldn't register top clock %i\n", i); + goto err_clk_unreg; + } + + hws[i] = &sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + clk_hw_unregister(&sclk->hw); + } + return ret; +} + +static void __init mt7621_clk_init(struct device_node *node) +{ + struct mt7621_clk_provider *clk_prov; + struct clk_hw_onecell_data **clk_data; + int ret, count; + + clk_prov = kzalloc(sizeof(*clk_prov), GFP_KERNEL); + if (!clk_prov) + return; + + clk_prov->syscon_regmap = syscon_regmap_lookup_by_phandle(node, "ralink,sysctl"); + if (IS_ERR(clk_prov->syscon_regmap)) { + pr_err("Could not get syscon regmap\n"); + goto free_clk_prov; + } + + clk_prov->node = node; + + clk_data = &clk_prov->clk_data; + count = ARRAY_SIZE(mt7621_clks_base) + ARRAY_SIZE(mt7621_gates); + *clk_data = kzalloc(struct_size(*clk_data, hws, count), GFP_KERNEL); + if (!*clk_data) + goto free_clk_prov; + + ret = mt7621_register_top_clocks(clk_prov); + if (ret) { + pr_err("Couldn't register top clocks\n"); + goto free_clk_data; + } + + ret = mt7621_register_fixed_clocks(clk_prov); + if (ret) { + pr_err("Couldn't register fixed clocks\n"); + goto free_clk_data; + } + + ret = mt7621_register_gates(clk_prov); + if (ret) { + pr_err("Couldn't register fixed clock gates\n"); + goto free_clk_data; + } + + of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_prov->clk_data); + + return; + +free_clk_data: + kfree(clk_prov->clk_data); + +free_clk_prov: + kfree(clk_prov); +} + +CLK_OF_DECLARE(mt7621_clk, "mediatek,mt7621-clk", mt7621_clk_init); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("Mediatek Mt7621 clock driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 15:46:29 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:29 +0100 Subject: [PATCH v3 2/5] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201113154632.24973-1-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> Message-ID: <20201113154632.24973-3-sergio.paracuellos@gmail.com> Adds device tree binding documentation for clocks in the MT7621 SOC. Signed-off-by: Sergio Paracuellos --- .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml new file mode 100644 index 000000000000..363bd9880e29 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT7621 Clock Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +description: | + The MT7621 has a PLL controller from where the cpu clock is provided + as well as derived clocks for the bus and the peripherals. It also + can gate SoC device clocks. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in: + [1]: . + +properties: + compatible: + const: mediatek,mt7621-clk + + ralink,sysctl: + $ref: /schemas/types.yaml#/definitions/phandle + description: + phandle to the syscon which is in the same address area with syscon + device. + + "#clock-cells": + description: + The first cell indicates the clock gate number, see [1] for available + clocks. + const: 1 + + clock-output-names: + maxItems: 8 + +required: + - compatible + - ralink,sysctl + - '#clock-cells' + - clock-output-names + +additionalProperties: false + +examples: + - | + #include + + pll { + compatible = "mediatek,mt7621-clk"; + ralink,sysctl = <&sysc>; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "250m", "270m"; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Fri Nov 13 15:46:32 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 13 Nov 2020 16:46:32 +0100 Subject: [PATCH v3 5/5] MAINTAINERS: add MT7621 CLOCK maintainer In-Reply-To: <20201113154632.24973-1-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> Message-ID: <20201113154632.24973-6-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 clock driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f1f088a29bc2..30822ad6837c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11142,6 +11142,12 @@ L: linux-wireless at vger.kernel.org S: Maintained F: drivers/net/wireless/mediatek/mt7601u/ +MEDIATEK MT7621 CLOCK DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml +F: drivers/clk/ralink/clk-mt7621.c + MEDIATEK MT7621/28/88 I2C DRIVER M: Stefan Roese L: linux-i2c at vger.kernel.org -- 2.25.1 From digetx at gmail.com Fri Nov 13 15:55:27 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 13 Nov 2020 18:55:27 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201113142937.GB4828@sirena.org.uk> References: <20201104234427.26477-12-digetx@gmail.com> <20201110202945.GF2375022@ulmo> <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> Message-ID: <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> 13.11.2020 17:29, Mark Brown ?????: > On Fri, Nov 13, 2020 at 01:37:01AM +0300, Dmitry Osipenko wrote: >> 12.11.2020 23:01, Mark Brown ?????: >>>> But it's not allowed to change voltage of a dummy regulator, is it >>>> intentional? > >>> Of course not, we can't know if the requested new voltage is valid - the >>> driver would have to have explict support for handling situations where >>> it's not possible to change the voltage (which it can detect through >>> enumerating the values it wants to set at startup). > >>> [Requesting the same supply multiple times] > >> But how driver is supposed to recognize that it's a dummy or buggy >> regulator if it rejects all voltages? > > It's not clear if it matters - it's more a policy decision on the part > of the driver about what it thinks safe error handling is. If it's not > possible to read voltages from the regulator the consumer driver has to > decide what it thinks it's safe for it to do, either way it has no idea > what the actual current voltage is. It could assume that it's something > that supports all the use cases it wants to use and just carry on with > no configuration of voltages, it could decide that it might not support > everything and not make any changes to be safe, or do something like > try to figure out that if we're currently at a given OPP that's the top > OPP possible. Historically when we've not had regulator control in > these drivers so they have effectively gone with the first option of > just assuming it's a generally safe value, this often aligns with what > the power on requirements for SoCs are so it's not unreasonable. I don't think that in a case of this particular driver there is a way to make any decisions other than to assume that all changes are safe to be done if regulator isn't specified in a device-tree. If regulator_get() returns a dummy regulator, then this means that regulator isn't specified in a device-tree. But then the only way for a consumer driver to check whether regulator is dummy, is to check presence of the supply property in a device-tree. We want to emit error messages when something goes wrong, for example when regulator voltage fails to change. It's fine that voltage changes are failing for a dummy regulator, but then consumer driver shouldn't recognize it as a error condition. The regulator_get_optional() provides a more consistent and straightforward way for consumer drivers to check presence of a physical voltage regulator in comparison to dealing with a regulator_get(). The dummy regulator is nice to use when there is no need to change regulator's voltage, which doesn't work for a dummy regulator. From digetx at gmail.com Fri Nov 13 16:00:57 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 13 Nov 2020 19:00:57 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> <20201112204358.GA1027187@ulmo> <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> Message-ID: <1f644c22-991c-7d27-b147-f12489e7ed7d@gmail.com> 13.11.2020 17:45, Ulf Hansson ?????: > On Thu, 12 Nov 2020 at 23:14, Dmitry Osipenko wrote: >> >> 12.11.2020 23:43, Thierry Reding ?????: >>>> The difference in comparison to using voltage regulator directly is >>>> minimal, basically the core-supply phandle is replaced is replaced with >>>> a power-domain phandle in a device tree. >>> These new power-domain handles would have to be added to devices that >>> potentially already have a power-domain handle, right? Isn't that going >>> to cause issues? I vaguely recall that we already have multiple power >>> domains for the XUSB controller and we have to jump through extra hoops >>> to make that work. >> >> I modeled the core PD as a parent of the PMC sub-domains, which >> presumably is a correct way to represent the domains topology. >> >> https://gist.github.com/digetx/dfd92c7f7e0aa6cef20403c4298088d7 > > That could make sense, it seems. > > Anyway, this made me realize that > dev_pm_genpd_set_performance_state(dev) returns -EINVAL, in case the > device's genpd doesn't have the ->set_performance_state() assigned. > This may not be correct. Instead we should likely consider an empty > callback as okay and continue to walk the topology upwards to the > parent domain, etc. > > Just wanted to point this out. I intend to post a patch as soon as I > can for this. Thank you, I was also going to make the same change, but haven't bothered to do it so far. Please feel free to CC me on the patch. From broonie at kernel.org Fri Nov 13 16:15:50 2020 From: broonie at kernel.org (Mark Brown) Date: Fri, 13 Nov 2020 16:15:50 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> References: <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> Message-ID: <20201113161550.GC4828@sirena.org.uk> On Fri, Nov 13, 2020 at 06:55:27PM +0300, Dmitry Osipenko wrote: > 13.11.2020 17:29, Mark Brown ?????: > > It's not clear if it matters - it's more a policy decision on the part > > of the driver about what it thinks safe error handling is. If it's not > If regulator_get() returns a dummy regulator, then this means that > regulator isn't specified in a device-tree. But then the only way for a > consumer driver to check whether regulator is dummy, is to check > presence of the supply property in a device-tree. My point here is that the driver shouldn't be checking for a dummy regulator, the driver should be checking the features that are provided to it by the regulator and handling those. It doesn't matter if this is a dummy regulator or an actual regulator with limited features, the effect is the same and the handling should be the same. If the driver is doing anything to handle dummy regulators explicitly as dummy regulators it is doing it wrong. > We want to emit error messages when something goes wrong, for example > when regulator voltage fails to change. It's fine that voltage changes > are failing for a dummy regulator, but then consumer driver shouldn't > recognize it as a error condition. If you're fine with that you should also be fine with any other regulator for which you failed to enumerate any voltages which you can set. > The regulator_get_optional() provides a more consistent and > straightforward way for consumer drivers to check presence of a physical > voltage regulator in comparison to dealing with a regulator_get(). The > dummy regulator is nice to use when there is no need to change > regulator's voltage, which doesn't work for a dummy regulator. To repeat you should *only* be using regulator_get_optional() in the case where the supply may be physically absent which is not the case here. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From thierry.reding at gmail.com Fri Nov 13 16:35:52 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Fri, 13 Nov 2020 17:35:52 +0100 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> <20201112204358.GA1027187@ulmo> <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> Message-ID: <20201113163552.GE1408970@ulmo> On Fri, Nov 13, 2020 at 01:14:45AM +0300, Dmitry Osipenko wrote: > 12.11.2020 23:43, Thierry Reding ?????: > >> The difference in comparison to using voltage regulator directly is > >> minimal, basically the core-supply phandle is replaced is replaced with > >> a power-domain phandle in a device tree. > > These new power-domain handles would have to be added to devices that > > potentially already have a power-domain handle, right? Isn't that going > > to cause issues? I vaguely recall that we already have multiple power > > domains for the XUSB controller and we have to jump through extra hoops > > to make that work. > > I modeled the core PD as a parent of the PMC sub-domains, which > presumably is a correct way to represent the domains topology. > > https://gist.github.com/digetx/dfd92c7f7e0aa6cef20403c4298088d7 > > >> The only thing which makes me feel a bit uncomfortable is that there is > >> no real hardware node for the power domain node in a device-tree. > > Could we anchor the new power domain at the PMC for example? That would > > allow us to avoid the "virtual" node. > > I had a thought about using PMC for the core domain, but not sure > whether it will be an entirely correct hardware description. Although, > it will be nice to have it this way. > > This is what Tegra TRM says about PMC: > > "The Power Management Controller (PMC) block interacts with an external > or Power Manager Unit (PMU). The PMC mostly controls the entry and exit > of the system from different sleep modes. It provides power-gating > controllers for SOC and CPU power-islands and also provides scratch > storage to save some of the context during sleep modes (when CPU and/or > SOC power rails are off). Additionally, PMC interacts with the external > Power Manager Unit (PMU)." > > The core voltage regulator is a part of the PMU. > > Not all core SoC devices are behind PMC, IIUC. There are usually some SoC devices that are always-on. Things like the RTC for example, can never be power-gated, as far as I recall. On newer chips there are usually many more blocks that can't be powergated at all. > > On the other hand, if we were to > > use a regulator, we'd be adding a node for that, right? So isn't this > > effectively going to be the same node if we use a power domain? Both > > software constructs are using the same voltage regulator, so they should > > be able to be described by the same device tree node, shouldn't they? > > I'm not exactly sure what you're meaning by "use a regulator" and "we'd > be adding a node for that", could you please clarify? This v1 approach > uses a core-supply phandle (i.e. regulator is used), it doesn't require > extra nodes. What I meant to say was that the actual supply voltage is generated by some device (typically one of the SD outputs of the PMIC). Whether we model this as a power domain or a regulator doesn't really matter, right? So I'm wondering if the device that generates the voltage should be the power domain provider, just like it is the provider of the regulator if this was modelled as a regulator. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From digetx at gmail.com Fri Nov 13 17:13:49 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Fri, 13 Nov 2020 20:13:49 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201113161550.GC4828@sirena.org.uk> References: <20201110203257.GC5957@sirena.org.uk> <72ae6462-13df-9fcb-510e-8e57eee0f035@gmail.com> <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> Message-ID: <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> 13.11.2020 19:15, Mark Brown ?????: > On Fri, Nov 13, 2020 at 06:55:27PM +0300, Dmitry Osipenko wrote: >> 13.11.2020 17:29, Mark Brown ?????: > >>> It's not clear if it matters - it's more a policy decision on the part >>> of the driver about what it thinks safe error handling is. If it's not > >> If regulator_get() returns a dummy regulator, then this means that >> regulator isn't specified in a device-tree. But then the only way for a >> consumer driver to check whether regulator is dummy, is to check >> presence of the supply property in a device-tree. > > My point here is that the driver shouldn't be checking for a dummy > regulator, the driver should be checking the features that are provided > to it by the regulator and handling those. I understand yours point, but then we need dummy regulator to provide all the features, and currently it does the opposite. > It doesn't matter if this is > a dummy regulator or an actual regulator with limited features, the > effect is the same and the handling should be the same. If the driver > is doing anything to handle dummy regulators explicitly as dummy > regulators it is doing it wrong. It matters because dummy regulator errors out all checks and changes other than enable/disable, instead of accepting them. If we could add an option for dummy regulator to succeed all the checks and accept all the values, then it could become more usable. >> We want to emit error messages when something goes wrong, for example >> when regulator voltage fails to change. It's fine that voltage changes >> are failing for a dummy regulator, but then consumer driver shouldn't >> recognize it as a error condition. > > If you're fine with that you should also be fine with any other > regulator for which you failed to enumerate any voltages which you can > set. It's not fine. In the case of this driver the dummy regulator should succeed instead of failing. >> The regulator_get_optional() provides a more consistent and >> straightforward way for consumer drivers to check presence of a physical >> voltage regulator in comparison to dealing with a regulator_get(). The >> dummy regulator is nice to use when there is no need to change >> regulator's voltage, which doesn't work for a dummy regulator. > > To repeat you should *only* be using regulator_get_optional() in the > case where the supply may be physically absent which is not the case > here. > Alright, but then we either need to improve regulator core to make dummy regulator a bit more usable, or continue to work around it in drivers. What should we do? From broonie at kernel.org Fri Nov 13 17:28:59 2020 From: broonie at kernel.org (Mark Brown) Date: Fri, 13 Nov 2020 17:28:59 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> References: <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> Message-ID: <20201113172859.GF4828@sirena.org.uk> On Fri, Nov 13, 2020 at 08:13:49PM +0300, Dmitry Osipenko wrote: > 13.11.2020 19:15, Mark Brown ?????: > > My point here is that the driver shouldn't be checking for a dummy > > regulator, the driver should be checking the features that are provided > > to it by the regulator and handling those. > I understand yours point, but then we need dummy regulator to provide > all the features, and currently it does the opposite. As could any other regulator? > > It doesn't matter if this is > > a dummy regulator or an actual regulator with limited features, the > > effect is the same and the handling should be the same. If the driver > > is doing anything to handle dummy regulators explicitly as dummy > > regulators it is doing it wrong. > It matters because dummy regulator errors out all checks and changes > other than enable/disable, instead of accepting them. If we could add an > option for dummy regulator to succeed all the checks and accept all the > values, then it could become more usable. I'm a bit confused here TBH - I'm not sure I see a substantial difference between a consumer detecting that it can't set any voltages at all and the handling for an optional regulator. Either way if it's going to carry on and assume that whatever voltage is there works for everything it boils down to setting a flag saying to skip the set voltage operation. I think you are too focused on the specific implementation you currently have here. We obviously can't just accept voltage change operations when we've no idea what the current voltage of the device is. > > To repeat you should *only* be using regulator_get_optional() in the > > case where the supply may be physically absent which is not the case > > here. > > Alright, but then we either need to improve regulator core to make dummy > regulator a bit more usable, or continue to work around it in drivers. > What should we do? As I keep saying the consumer driver should be enumerating the voltages it can set, if it can't find any and wants to continue then it can just skip setting voltages later on. If only some are unavailable then it probably wants to eliminate those specific OPPs instead. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From thierry.reding at gmail.com Fri Nov 13 17:30:42 2020 From: thierry.reding at gmail.com (Thierry Reding) Date: Fri, 13 Nov 2020 18:30:42 +0100 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> References: <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> Message-ID: <20201113173042.GA1416567@ulmo> On Fri, Nov 13, 2020 at 08:13:49PM +0300, Dmitry Osipenko wrote: > 13.11.2020 19:15, Mark Brown ?????: > > On Fri, Nov 13, 2020 at 06:55:27PM +0300, Dmitry Osipenko wrote: > >> 13.11.2020 17:29, Mark Brown ?????: > > > >>> It's not clear if it matters - it's more a policy decision on the part > >>> of the driver about what it thinks safe error handling is. If it's not > > > >> If regulator_get() returns a dummy regulator, then this means that > >> regulator isn't specified in a device-tree. But then the only way for a > >> consumer driver to check whether regulator is dummy, is to check > >> presence of the supply property in a device-tree. > > > > My point here is that the driver shouldn't be checking for a dummy > > regulator, the driver should be checking the features that are provided > > to it by the regulator and handling those. > > I understand yours point, but then we need dummy regulator to provide > all the features, and currently it does the opposite. But that's exactly Mark's point. Any regular regulator could be lacking all of the features just as well. If the regulator supports a fixed voltage, then it's not going to allow you to set a different one, etc. The point is that the regulator consumer should then be written in a way to deal with varying levels of features. Thierry -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 833 bytes Desc: not available URL: From skhan at linuxfoundation.org Fri Nov 13 17:46:11 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Fri, 13 Nov 2020 10:46:11 -0700 Subject: [PATCH v2 09/13] drivers/staging/rtl8723bs: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <34ff683c46a964194a272b63f7baf2206c201d88.1605287778.git.skhan@linuxfoundation.org> Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath. Convert it to use seqnum_ops. atomic_t variables used for stats are atomic counters. Convert them to use seqnum_ops. Signed-off-by: Shuah Khan --- drivers/staging/rtl8723bs/core/rtw_cmd.c | 3 +- drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 33 +++++++++++++------ drivers/staging/rtl8723bs/include/rtw_cmd.h | 3 +- .../staging/rtl8723bs/include/rtw_mlme_ext.h | 3 +- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 2abe205e3453..a82a0d9af3b0 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -10,6 +10,7 @@ #include #include #include +#include static struct _cmd_callback rtw_cmd_callback[] = { {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/ @@ -207,7 +208,7 @@ static void c2h_wk_callback(_workitem * work); int rtw_init_evt_priv(struct evt_priv *pevtpriv) { /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */ - atomic_set(&pevtpriv->event_seq, 0); + seqnum32_init(&pevtpriv->event_seq); pevtpriv->evt_done_cnt = 0; _init_workitem(&pevtpriv->c2h_wk, c2h_wk_callback, NULL); diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index b912ad2f4b72..48be6049b45c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -11,6 +11,7 @@ #include #include #include +#include #include static struct mlme_handler mlme_sta_tbl[] = { @@ -281,7 +282,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; - atomic_set(&pmlmeext->event_seq, 0); + seqnum32_init(&pmlmeext->event_seq); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ pmlmeext->sa_query_seq = 0; pmlmeext->mgnt_80211w_IPN = 0; @@ -5051,7 +5052,9 @@ void report_survey_event(struct adapter *padapter, union recv_frame *precv_frame pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); @@ -5104,7 +5107,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -5151,7 +5156,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pjoinbss_evt->network.network)), &(pmlmeinfo->network), sizeof(struct wlan_bssid_ex)); @@ -5202,7 +5209,9 @@ void report_wmm_edca_update(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct wmm_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_WMM); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); pwmm_event = (struct wmm_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); pwmm_event->wmm = 0; @@ -5249,7 +5258,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, unsi pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(pdel_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -5302,7 +5313,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, int pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA); - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&(padd_sta_evt->macaddr)), MacAddr, ETH_ALEN); @@ -6620,10 +6633,10 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) #ifdef CHECK_EVENT_SEQ /* checking event sequence... */ - if (evt_seq != (atomic_read(&pevt_priv->event_seq) & 0x7f)) { + if (evt_seq != (seqnum32_fetch(&pevt_priv->event_seq) & 0x7f)) { RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_, ("Event Seq Error! %d vs %d\n", (evt_seq & 0x7f), - (atomic_read(&pevt_priv->event_seq) & 0x7f))); + (seqnum32_fetch(&pevt_priv->event_seq) & 0x7f))); pevt_priv->event_seq = (evt_seq+1)&0x7f; @@ -6647,7 +6660,7 @@ u8 mlme_evt_hdl(struct adapter *padapter, unsigned char *pbuf) } - atomic_inc(&pevt_priv->event_seq); + seqnum32_inc_return(&pevt_priv->event_seq); peventbuf += 2; diff --git a/drivers/staging/rtl8723bs/include/rtw_cmd.h b/drivers/staging/rtl8723bs/include/rtw_cmd.h index 56c77bc7ca81..cc0ea649388b 100644 --- a/drivers/staging/rtl8723bs/include/rtw_cmd.h +++ b/drivers/staging/rtl8723bs/include/rtw_cmd.h @@ -8,6 +8,7 @@ #define __RTW_CMD_H_ #include +#include #define C2H_MEM_SZ (16*1024) @@ -62,7 +63,7 @@ struct rtw_cbuf *c2h_queue; #define C2H_QUEUE_MAX_LEN 10 - atomic_t event_seq; + struct seqnum32 event_seq; u8 *evt_buf; /* shall be non-paged, and 4 bytes aligned */ u8 *evt_allocated_buf; u32 evt_done_cnt; diff --git a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h index 1567831caf91..537813c00670 100644 --- a/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8723bs/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_ +#include /* Commented by Albert 20101105 */ /* Increase the SURVEY_TO value from 100 to 150 (100ms to 150ms) */ @@ -461,7 +462,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq; u16 sa_query_seq; u64 mgnt_80211w_IPN; -- 2.27.0 From skhan at linuxfoundation.org Fri Nov 13 17:46:14 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Fri, 13 Nov 2020 10:46:14 -0700 Subject: [PATCH v2 12/13] drivers/staging/unisys/visorhba: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <948df30739a497922bafa4637f63218e9ec44e61.1605287778.git.skhan@linuxfoundation.org> Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath. Convert it to use seqnum_ops. atomic_t variable used for error_count are atomic counters. Convert it to use seqnum_ops. Signed-off-by: Shuah Khan --- .../staging/unisys/visorhba/visorhba_main.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/staging/unisys/visorhba/visorhba_main.c b/drivers/staging/unisys/visorhba/visorhba_main.c index 7ae5306b92fe..7837eca83758 100644 --- a/drivers/staging/unisys/visorhba/visorhba_main.c +++ b/drivers/staging/unisys/visorhba/visorhba_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -42,7 +43,7 @@ struct visordisk_info { struct scsi_device *sdev; u32 valid; atomic_t ios_threshold; - atomic_t error_count; + struct seqnum32 error_count; struct visordisk_info *next; }; @@ -374,8 +375,8 @@ static int visorhba_abort_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_fetch(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc_return(&vdisk->error_count); else atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); rtn = forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsidev); @@ -401,8 +402,8 @@ static int visorhba_device_reset_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_fetch(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc_return(&vdisk->error_count); else atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); rtn = forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsidev); @@ -429,8 +430,8 @@ static int visorhba_bus_reset_handler(struct scsi_cmnd *scsicmd) scsidev = scsicmd->device; shost_for_each_device(scsidev, scsidev->host) { vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) - atomic_inc(&vdisk->error_count); + if (seqnum32_fetch(&vdisk->error_count) < VISORHBA_ERROR_COUNT) + seqnum32_inc_return(&vdisk->error_count); else atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } @@ -803,8 +804,8 @@ static void do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, return; /* Okay see what our error_count is here.... */ vdisk = scsidev->hostdata; - if (atomic_read(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { - atomic_inc(&vdisk->error_count); + if (seqnum32_fetch(&vdisk->error_count) < VISORHBA_ERROR_COUNT) { + seqnum32_inc_return(&vdisk->error_count); atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); } } @@ -884,7 +885,7 @@ static void do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, if (atomic_read(&vdisk->ios_threshold) > 0) { atomic_dec(&vdisk->ios_threshold); if (atomic_read(&vdisk->ios_threshold) == 0) - atomic_set(&vdisk->error_count, 0); + seqnum32_init(&vdisk->error_count); } } } -- 2.27.0 From skhan at linuxfoundation.org Fri Nov 13 17:46:13 2020 From: skhan at linuxfoundation.org (Shuah Khan) Date: Fri, 13 Nov 2020 10:46:13 -0700 Subject: [PATCH v2 11/13] drivers/staging/rtl8188eu: convert stats to use seqnum_ops In-Reply-To: References: Message-ID: <9862cdd72a54d11dc0d08489df4c19902aab3785.1605287778.git.skhan@linuxfoundation.org> Sequence Number api provides interfaces for unsigned atomic up counters leveraging atomic_t and atomic64_t ops underneath. Convert it to use seqnum_ops. atomic_t variables used for stats are atomic counters. Convert them to use seqnum_ops. Signed-off-by: Shuah Khan --- drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | 23 ++++++++++++++----- .../staging/rtl8188eu/include/rtw_mlme_ext.h | 3 ++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index b3eddcb83cd0..d8b5ab1dac26 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -7,6 +7,7 @@ #define _RTW_MLME_EXT_C_ #include +#include #include #include @@ -3860,7 +3861,7 @@ static void init_mlme_ext_priv_value(struct adapter *padapter) _12M_RATE_, _24M_RATE_, 0xff, }; - atomic_set(&pmlmeext->event_seq, 0); + seqnum32_init(&pmlmeext->event_seq); pmlmeext->mgnt_seq = 0;/* reset to zero when disconnect at client mode */ pmlmeext->cur_channel = padapter->registrypriv.channel; @@ -4189,7 +4190,9 @@ void report_survey_event(struct adapter *padapter, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct survey_event); pc2h_evt_hdr->ID = _Survey_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); psurvey_evt = (struct survey_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); @@ -4239,7 +4242,9 @@ void report_surveydone_event(struct adapter *padapter) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct surveydone_event); pc2h_evt_hdr->ID = _SurveyDone_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); psurveydone_evt = (struct surveydone_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt; @@ -4283,7 +4288,9 @@ void report_join_res(struct adapter *padapter, int res) pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct joinbss_event); pc2h_evt_hdr->ID = _JoinBss_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); pjoinbss_evt = (struct joinbss_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); memcpy((unsigned char *)(&pjoinbss_evt->network.network), &pmlmeinfo->network, sizeof(struct wlan_bssid_ex)); @@ -4333,7 +4340,9 @@ void report_del_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stadel_event); pc2h_evt_hdr->ID = _DelSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); pdel_sta_evt = (struct stadel_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&pdel_sta_evt->macaddr), MacAddr); @@ -4386,7 +4395,9 @@ void report_add_sta_event(struct adapter *padapter, unsigned char *MacAddr, pc2h_evt_hdr = (struct C2HEvent_Header *)(pevtcmd); pc2h_evt_hdr->len = sizeof(struct stassoc_event); pc2h_evt_hdr->ID = _AddSTA_EVT_; - pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq); + + /* seq is unsigned int seq:8 */ + pc2h_evt_hdr->seq = seqnum32_inc_return(&pmlmeext->event_seq); padd_sta_evt = (struct stassoc_event *)(pevtcmd + sizeof(struct C2HEvent_Header)); ether_addr_copy((unsigned char *)(&padd_sta_evt->macaddr), MacAddr); diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h index b11a6886a083..09b7e3bb2738 100644 --- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h +++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h @@ -7,6 +7,7 @@ #ifndef __RTW_MLME_EXT_H_ #define __RTW_MLME_EXT_H_ +#include #include #include #include @@ -393,7 +394,7 @@ struct p2p_oper_class_map { struct mlme_ext_priv { struct adapter *padapter; u8 mlmeext_init; - atomic_t event_seq; + struct seqnum32 event_seq; u16 mgnt_seq; unsigned char cur_channel; -- 2.27.0 From gregkh at linuxfoundation.org Fri Nov 13 23:20:51 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Sat, 14 Nov 2020 00:20:51 +0100 Subject: [PATCH] staging: mt7621-pci: avoid to request pci bus resources In-Reply-To: References: <20201102202515.19073-1-sergio.paracuellos@gmail.com> Message-ID: On Fri, Nov 13, 2020 at 04:26:08PM +0100, Sergio Paracuellos wrote: > Hi Greg, > > On Mon, Nov 2, 2020 at 9:25 PM Sergio Paracuellos > wrote: > > > > After upgrading kernel to version 5.9.x the driver was not > > working anymore showing the following kernel trace: > > > > ... > > mt7621-pci 1e140000.pcie: resource collision: > > [mem 0x60000000-0x6fffffff] conflicts with pcie at 1e140000 [mem 0x60000000-0x6fffffff] > > ------------[ cut here ]------------ > > WARNING: CPU: 2 PID: 73 at kernel/resource.c:1400 > > devm_request_resource+0xfc/0x10c > > Modules linked in: > > CPU: 2 PID: 73 Comm: kworker/2:1 Not tainted 5.9.2 #0 > > Workqueue: events deferred_probe_work_func > > Stack : 00000000 81590000 807d0a1c 808a0000 8fd49080 > > 807d0000 00000009 808ac820 > > 00000001 808338d0 7fff0001 800839dc 00000049 > > 00000001 8fe51b00 367204ab > > 00000000 00000000 807d0a1c 807c0000 00000001 > > 80082358 8fe50000 00559000 > > 00000000 8fe519f1 ffffffff 00000005 00000000 > > 00000001 00000000 807d0000 > > 00000009 808ac820 00000001 808338d0 00000001 > > 803bf1b0 00000008 81390008 > > > > Call Trace: > > [<8000d018>] show_stack+0x30/0x100 > > [<8032e66c>] dump_stack+0xa4/0xd4 > > [<8002db1c>] __warn+0xc0/0x134 > > [<8002dbec>] warn_slowpath_fmt+0x5c/0xac > > [<80033b34>] devm_request_resource+0xfc/0x10c > > [<80365ff8>] devm_request_pci_bus_resources+0x58/0xdc > > [<8048e13c>] mt7621_pci_probe+0x8dc/0xe48 > > [<803d2140>] platform_drv_probe+0x40/0x94 > > [<803cfd94>] really_probe+0x108/0x4ec > > [<803cd958>] bus_for_each_drv+0x70/0xb0 > > [<803d0388>] __device_attach+0xec/0x164 > > [<803cec8c>] bus_probe_device+0xa4/0xc0 > > [<803cf1c4>] deferred_probe_work_func+0x80/0xc4 > > [<80048444>] process_one_work+0x260/0x510 > > [<80048a4c>] worker_thread+0x358/0x5cc > > [<8004f7d0>] kthread+0x134/0x13c > > [<80007478>] ret_from_kernel_thread+0x14/0x1c > > ---[ end trace a9dd2e37537510d3 ]--- > > mt7621-pci 1e140000.pcie: Error requesting resources > > mt7621-pci: probe of 1e140000.pcie failed with error -16 > > ... > > > > With commit 669cbc708122 ("PCI: Move DT resource setup into > > devm_pci_alloc_host_bridge()"), the DT 'ranges' is parsed and populated > > into resources when the host bridge is allocated. The resources are > > requested as well, but that happens a 2nd time for this driver in > > mt7621_pcie_request_resources(). Hence we should avoid this second > > request. > > > > Also, the bus ranges was also populated by default, so we can remove > > it from mt7621_pcie_request_resources() to avoid the following trace > > if we don't avoid it: > > > > pci_bus 0000:00: busn_res: can not insert [bus 00-ff] > > under domain [bus 00-ff] (conflicts with (null) [bus 00-ff]) > > > > Function 'mt7621_pcie_request_resources' has been renamed into > > 'mt7621_pcie_add_resources' which now is a more accurate name > > for this function. > > > > Cc: stable at vger.kernel.org#5.9.x- > > Signed-off-by: Sergio Paracuellos > > This patch have to be added also for stable 5.9.x because driver is > broken in all kernel 5.9.x releases. I noticed a new stable release > comes three days ago (5.9.8) and this was not added. I was wondering > if the way I marked this patch to be included is wrong. Is this patch in Linus's tree yet? If not, we can't add it to any stable tree. That has to happen first. thanks, greg k-h From gregkh at linuxfoundation.org Fri Nov 13 23:27:28 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Sat, 14 Nov 2020 00:27:28 +0100 Subject: [PATCH 2/2] staging: greybus: audio: apbridgea: Fix reference counter leak in error handling In-Reply-To: <20201109131347.1725288-3-zhangqilong3@huawei.com> References: <20201109131347.1725288-1-zhangqilong3@huawei.com> <20201109131347.1725288-3-zhangqilong3@huawei.com> Message-ID: On Mon, Nov 09, 2020 at 09:13:47PM +0800, Zhang Qilong wrote: > When gb_audio_apbridgea_register_cport failed, maybe: > > 1) gb_pm_runtime_get_sync failed, usage counter remained unchanged; > > 2) gb_hd_output failed, usage counter remained increased; > > In error state, there are two different states in usage cpounter. So, > if gb_hd_output failed, we should call gb_pm_runtime_put_autosuspend > ot decrease usage counter for balabce preventing reference leak. And > we fixed it by add gb_pm_runtime_put_autosuspend when gb_hd_output > failed. > > Fixes: 6ba7fad430d63 ("Add runtime pm support to audio protocol device class driver.") That is not the name for that git commit id :( Please fix up and resend. thanks, greg k-h From zhangqilong3 at huawei.com Sat Nov 14 03:17:41 2020 From: zhangqilong3 at huawei.com (Zhang Qilong) Date: Sat, 14 Nov 2020 11:17:41 +0800 Subject: [PATCH v2 2/2] greybus: audio: apbridgea: Fix reference counter leak in error handling Message-ID: <20201114031741.3036814-1-zhangqilong3@huawei.com> When gb_audio_apbridgea_register_cport failed, maybe: 1) gb_pm_runtime_get_sync failed, usage counter remained unchanged; 2) gb_hd_output failed, usage counter remained increased; In error state, there are two different states in usage cpounter. So, if gb_hd_output failed, we should call gb_pm_runtime_put_autosuspend ot decrease usage counter for balabce preventing reference leak. And we fixed it by add gb_pm_runtime_put_autosuspend when gb_hd_output failed. Fixes: 6ba7fad430d63 ("greybus: audio: add runtime pm support") Signed-off-by: Zhang Qilong --- Changelog: v2 - fix the name for fixed commit id --- drivers/staging/greybus/audio_apbridgea.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio_apbridgea.c b/drivers/staging/greybus/audio_apbridgea.c index 26117e390deb..50545fd9756c 100644 --- a/drivers/staging/greybus/audio_apbridgea.c +++ b/drivers/staging/greybus/audio_apbridgea.c @@ -42,8 +42,12 @@ int gb_audio_apbridgea_register_cport(struct gb_connection *connection, if (ret) return ret; - return gb_hd_output(connection->hd, &req, sizeof(req), + ret = gb_hd_output(connection->hd, &req, sizeof(req), GB_APB_REQUEST_AUDIO_CONTROL, true); + if (ret) + gb_pm_runtime_put_autosuspend(connection->bundle); + + return ret; } EXPORT_SYMBOL_GPL(gb_audio_apbridgea_register_cport); -- 2.25.4 From sergio.paracuellos at gmail.com Sat Nov 14 07:24:06 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 14 Nov 2020 08:24:06 +0100 Subject: [PATCH] staging: mt7621-pci: avoid to request pci bus resources In-Reply-To: References: <20201102202515.19073-1-sergio.paracuellos@gmail.com> Message-ID: On Sat, Nov 14, 2020 at 12:19 AM Greg KH wrote: > > On Fri, Nov 13, 2020 at 04:26:08PM +0100, Sergio Paracuellos wrote: > > Hi Greg, > > > > On Mon, Nov 2, 2020 at 9:25 PM Sergio Paracuellos > > wrote: > > > > > > After upgrading kernel to version 5.9.x the driver was not > > > working anymore showing the following kernel trace: > > > > > > ... > > > mt7621-pci 1e140000.pcie: resource collision: > > > [mem 0x60000000-0x6fffffff] conflicts with pcie at 1e140000 [mem 0x60000000-0x6fffffff] > > > ------------[ cut here ]------------ > > > WARNING: CPU: 2 PID: 73 at kernel/resource.c:1400 > > > devm_request_resource+0xfc/0x10c > > > Modules linked in: > > > CPU: 2 PID: 73 Comm: kworker/2:1 Not tainted 5.9.2 #0 > > > Workqueue: events deferred_probe_work_func > > > Stack : 00000000 81590000 807d0a1c 808a0000 8fd49080 > > > 807d0000 00000009 808ac820 > > > 00000001 808338d0 7fff0001 800839dc 00000049 > > > 00000001 8fe51b00 367204ab > > > 00000000 00000000 807d0a1c 807c0000 00000001 > > > 80082358 8fe50000 00559000 > > > 00000000 8fe519f1 ffffffff 00000005 00000000 > > > 00000001 00000000 807d0000 > > > 00000009 808ac820 00000001 808338d0 00000001 > > > 803bf1b0 00000008 81390008 > > > > > > Call Trace: > > > [<8000d018>] show_stack+0x30/0x100 > > > [<8032e66c>] dump_stack+0xa4/0xd4 > > > [<8002db1c>] __warn+0xc0/0x134 > > > [<8002dbec>] warn_slowpath_fmt+0x5c/0xac > > > [<80033b34>] devm_request_resource+0xfc/0x10c > > > [<80365ff8>] devm_request_pci_bus_resources+0x58/0xdc > > > [<8048e13c>] mt7621_pci_probe+0x8dc/0xe48 > > > [<803d2140>] platform_drv_probe+0x40/0x94 > > > [<803cfd94>] really_probe+0x108/0x4ec > > > [<803cd958>] bus_for_each_drv+0x70/0xb0 > > > [<803d0388>] __device_attach+0xec/0x164 > > > [<803cec8c>] bus_probe_device+0xa4/0xc0 > > > [<803cf1c4>] deferred_probe_work_func+0x80/0xc4 > > > [<80048444>] process_one_work+0x260/0x510 > > > [<80048a4c>] worker_thread+0x358/0x5cc > > > [<8004f7d0>] kthread+0x134/0x13c > > > [<80007478>] ret_from_kernel_thread+0x14/0x1c > > > ---[ end trace a9dd2e37537510d3 ]--- > > > mt7621-pci 1e140000.pcie: Error requesting resources > > > mt7621-pci: probe of 1e140000.pcie failed with error -16 > > > ... > > > > > > With commit 669cbc708122 ("PCI: Move DT resource setup into > > > devm_pci_alloc_host_bridge()"), the DT 'ranges' is parsed and populated > > > into resources when the host bridge is allocated. The resources are > > > requested as well, but that happens a 2nd time for this driver in > > > mt7621_pcie_request_resources(). Hence we should avoid this second > > > request. > > > > > > Also, the bus ranges was also populated by default, so we can remove > > > it from mt7621_pcie_request_resources() to avoid the following trace > > > if we don't avoid it: > > > > > > pci_bus 0000:00: busn_res: can not insert [bus 00-ff] > > > under domain [bus 00-ff] (conflicts with (null) [bus 00-ff]) > > > > > > Function 'mt7621_pcie_request_resources' has been renamed into > > > 'mt7621_pcie_add_resources' which now is a more accurate name > > > for this function. > > > > > > Cc: stable at vger.kernel.org#5.9.x- > > > Signed-off-by: Sergio Paracuellos > > > > This patch have to be added also for stable 5.9.x because driver is > > broken in all kernel 5.9.x releases. I noticed a new stable release > > comes three days ago (5.9.8) and this was not added. I was wondering > > if the way I marked this patch to be included is wrong. > > Is this patch in Linus's tree yet? If not, we can't add it to any > stable tree. That has to happen first. > Ahh, ok I see. No, it is not in the linux tree yet. It is still in your staging-linus branch. I did not know that, thanks for let me know . > thanks, > > greg k-h Best regards, Sergio Paracuellos From lkp at intel.com Sat Nov 14 07:34:32 2020 From: lkp at intel.com (kernel test robot) Date: Sat, 14 Nov 2020 15:34:32 +0800 Subject: [staging:staging-linus] BUILD SUCCESS 18db36a073db6377a52e22ec44eb0500f0a0ecc6 Message-ID: <5faf8888.jWcbi/upa0ZRLDaB%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-linus branch HEAD: 18db36a073db6377a52e22ec44eb0500f0a0ecc6 docs: ABI: testing: iio: stm32: remove re-introduced unsupported ABI elapsed time: 720m configs tested: 153 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig arm hackkit_defconfig mips rm200_defconfig sh r7785rp_defconfig ia64 alldefconfig arm collie_defconfig mips workpad_defconfig nios2 10m50_defconfig arm ep93xx_defconfig arm nhk8815_defconfig powerpc sam440ep_defconfig mips allyesconfig h8300 h8300h-sim_defconfig sh shx3_defconfig xtensa defconfig powerpc iss476-smp_defconfig powerpc sequoia_defconfig powerpc eiger_defconfig arm neponset_defconfig powerpc kmeter1_defconfig m68k defconfig m68k m5307c3_defconfig powerpc mgcoge_defconfig sh sdk7780_defconfig arm lubbock_defconfig mips e55_defconfig xtensa cadence_csp_defconfig nios2 alldefconfig sh rsk7203_defconfig m68k q40_defconfig openrisc or1ksim_defconfig powerpc storcenter_defconfig sparc sparc32_defconfig powerpc ppa8548_defconfig arm gemini_defconfig m68k m5249evb_defconfig arm iop32x_defconfig arm simpad_defconfig arm sunxi_defconfig powerpc mpc866_ads_defconfig sh ecovec24-romimage_defconfig arm64 alldefconfig arm h5000_defconfig powerpc pmac32_defconfig mips sb1250_swarm_defconfig powerpc mpc832x_rdb_defconfig mips omega2p_defconfig powerpc cm5200_defconfig powerpc bamboo_defconfig mips bcm47xx_defconfig powerpc64 alldefconfig sh sh7724_generic_defconfig alpha alldefconfig arm s3c6400_defconfig arm vf610m4_defconfig arm integrator_defconfig sh ecovec24_defconfig sh se7750_defconfig mips jazz_defconfig powerpc acadia_defconfig xtensa iss_defconfig nds32 alldefconfig arm aspeed_g4_defconfig arm assabet_defconfig um kunit_defconfig xtensa virt_defconfig arm shmobile_defconfig powerpc64 defconfig arm sama5_defconfig mips ip32_defconfig riscv defconfig sh kfr2r09_defconfig mips loongson1c_defconfig arm milbeaut_m10v_defconfig arm spitz_defconfig mips tb0226_defconfig m68k m5272c3_defconfig arm imx_v4_v5_defconfig powerpc pq2fads_defconfig powerpc mvme5100_defconfig ia64 generic_defconfig arm stm32_defconfig mips bcm63xx_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a006-20201113 i386 randconfig-a005-20201113 i386 randconfig-a002-20201113 i386 randconfig-a001-20201113 i386 randconfig-a003-20201113 i386 randconfig-a004-20201113 x86_64 randconfig-a015-20201113 x86_64 randconfig-a011-20201113 x86_64 randconfig-a014-20201113 x86_64 randconfig-a013-20201113 x86_64 randconfig-a016-20201113 x86_64 randconfig-a012-20201113 i386 randconfig-a012-20201113 i386 randconfig-a014-20201113 i386 randconfig-a016-20201113 i386 randconfig-a011-20201113 i386 randconfig-a015-20201113 i386 randconfig-a013-20201113 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a003-20201113 x86_64 randconfig-a005-20201113 x86_64 randconfig-a004-20201113 x86_64 randconfig-a002-20201113 x86_64 randconfig-a006-20201113 x86_64 randconfig-a001-20201113 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From lkp at intel.com Sat Nov 14 07:40:57 2020 From: lkp at intel.com (kernel test robot) Date: Sat, 14 Nov 2020 15:40:57 +0800 Subject: [staging:staging-testing] BUILD SUCCESS 0d79a48440f559ac939d1be2089757c5e4ab16c7 Message-ID: <5faf8a09.ghaxvlbjV1Gmq4uC%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: 0d79a48440f559ac939d1be2089757c5e4ab16c7 staging: vt6655: Remove useless else elapsed time: 726m configs tested: 170 configs skipped: 3 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig arm hackkit_defconfig mips rm200_defconfig sh r7785rp_defconfig ia64 alldefconfig arm collie_defconfig powerpc sam440ep_defconfig mips allyesconfig h8300 h8300h-sim_defconfig sh shx3_defconfig xtensa defconfig powerpc iss476-smp_defconfig powerpc sequoia_defconfig powerpc eiger_defconfig arm neponset_defconfig powerpc kmeter1_defconfig m68k m5307c3_defconfig powerpc mgcoge_defconfig sh sdk7780_defconfig arm lubbock_defconfig mips e55_defconfig xtensa cadence_csp_defconfig nios2 alldefconfig sh rsk7203_defconfig m68k q40_defconfig openrisc or1ksim_defconfig powerpc storcenter_defconfig sparc sparc32_defconfig powerpc ppa8548_defconfig arm gemini_defconfig m68k m5249evb_defconfig arm iop32x_defconfig arm simpad_defconfig arm sunxi_defconfig mips rt305x_defconfig powerpc bluestone_defconfig powerpc mpc834x_itxgp_defconfig arm pxa255-idp_defconfig powerpc tqm8560_defconfig powerpc mpc866_ads_defconfig sh ecovec24-romimage_defconfig arm64 alldefconfig arm h5000_defconfig powerpc pmac32_defconfig mips sb1250_swarm_defconfig powerpc mpc832x_rdb_defconfig mips omega2p_defconfig powerpc cm5200_defconfig powerpc bamboo_defconfig mips bcm47xx_defconfig powerpc64 alldefconfig sh sh7724_generic_defconfig alpha alldefconfig arm s3c6400_defconfig arm vf610m4_defconfig arm integrator_defconfig sh ecovec24_defconfig sh se7750_defconfig mips jazz_defconfig powerpc acadia_defconfig xtensa iss_defconfig nds32 alldefconfig arm aspeed_g4_defconfig arm assabet_defconfig um kunit_defconfig powerpc chrp32_defconfig sh j2_defconfig powerpc rainier_defconfig m68k mac_defconfig mips vocore2_defconfig xtensa virt_defconfig arm shmobile_defconfig powerpc64 defconfig arm sama5_defconfig mips ip32_defconfig riscv defconfig sh kfr2r09_defconfig mips loongson1c_defconfig arm milbeaut_m10v_defconfig arm spitz_defconfig mips tb0226_defconfig m68k m5272c3_defconfig arm imx_v4_v5_defconfig powerpc pq2fads_defconfig powerpc mvme5100_defconfig ia64 generic_defconfig arm stm32_defconfig mips bcm63xx_defconfig arc haps_hs_smp_defconfig powerpc mpc8540_ads_defconfig powerpc g5_defconfig sparc sparc64_defconfig mips pistachio_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a006-20201113 i386 randconfig-a005-20201113 i386 randconfig-a002-20201113 i386 randconfig-a001-20201113 i386 randconfig-a003-20201113 i386 randconfig-a004-20201113 x86_64 randconfig-a015-20201113 x86_64 randconfig-a011-20201113 x86_64 randconfig-a014-20201113 x86_64 randconfig-a013-20201113 x86_64 randconfig-a016-20201113 x86_64 randconfig-a012-20201113 i386 randconfig-a012-20201113 i386 randconfig-a014-20201113 i386 randconfig-a016-20201113 i386 randconfig-a011-20201113 i386 randconfig-a015-20201113 i386 randconfig-a013-20201113 x86_64 randconfig-a003-20201114 x86_64 randconfig-a005-20201114 x86_64 randconfig-a004-20201114 x86_64 randconfig-a002-20201114 x86_64 randconfig-a001-20201114 x86_64 randconfig-a006-20201114 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a003-20201113 x86_64 randconfig-a005-20201113 x86_64 randconfig-a004-20201113 x86_64 randconfig-a002-20201113 x86_64 randconfig-a006-20201113 x86_64 randconfig-a001-20201113 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From xiakaixu1987 at gmail.com Sun Nov 15 12:13:20 2020 From: xiakaixu1987 at gmail.com (xiakaixu1987 at gmail.com) Date: Sun, 15 Nov 2020 20:13:20 +0800 Subject: [PATCH] staging: rtl8188eu: clean up the useless code Message-ID: <1605442400-16108-1-git-send-email-kaixuxia@tencent.com> From: Kaixu Xia The two bool variables singletone and carrier_sup are always false and the following if statement can't be true, these code are useless, so remove them. Reported-by: Tosk Robot Signed-off-by: Kaixu Xia --- drivers/staging/rtl8188eu/hal/phy.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/staging/rtl8188eu/hal/phy.c b/drivers/staging/rtl8188eu/hal/phy.c index a970189ba8c6..a664bff370bb 100644 --- a/drivers/staging/rtl8188eu/hal/phy.c +++ b/drivers/staging/rtl8188eu/hal/phy.c @@ -1200,7 +1200,6 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery) bool pathaok, pathbok; s32 reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4; bool is12simular, is13simular, is23simular; - bool singletone = false, carrier_sup = false; u32 iqk_bb_reg_92c[IQK_BB_REG_NUM] = { rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance, rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable, @@ -1214,9 +1213,6 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery) if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) return; - if (singletone || carrier_sup) - return; - if (recovery) { ODM_RT_TRACE(dm_odm, ODM_COMP_INIT, ODM_DBG_LOUD, ("phy_iq_calibrate: Return due to recovery!\n")); @@ -1312,14 +1308,11 @@ void rtl88eu_phy_iq_calibrate(struct adapter *adapt, bool recovery) void rtl88eu_phy_lc_calibrate(struct adapter *adapt) { - bool singletone = false, carrier_sup = false; u32 timeout = 2000, timecount = 0; struct odm_dm_struct *dm_odm = &adapt->HalData->odmpriv; if (!(dm_odm->SupportAbility & ODM_RF_CALIBRATION)) return; - if (singletone || carrier_sup) - return; while (*dm_odm->pbScanInProcess && timecount < timeout) { mdelay(50); -- 2.20.0 From digetx at gmail.com Sun Nov 15 16:29:48 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Sun, 15 Nov 2020 19:29:48 +0300 Subject: [PATCH v1 00/30] Introduce core voltage scaling for NVIDIA Tegra20/30 SoCs In-Reply-To: <20201113163552.GE1408970@ulmo> References: <20201104234427.26477-1-digetx@gmail.com> <2716c195-083a-112f-f1e5-2f6b7152a4b5@gmail.com> <1f7e90c4-6134-2e2b-4869-5afbda18ead3@gmail.com> <20201112204358.GA1027187@ulmo> <25942da9-b527-c0aa-5403-53c9cc34ad93@gmail.com> <20201113163552.GE1408970@ulmo> Message-ID: 13.11.2020 19:35, Thierry Reding ?????: > On Fri, Nov 13, 2020 at 01:14:45AM +0300, Dmitry Osipenko wrote: >> 12.11.2020 23:43, Thierry Reding ?????: >>>> The difference in comparison to using voltage regulator directly is >>>> minimal, basically the core-supply phandle is replaced is replaced with >>>> a power-domain phandle in a device tree. >>> These new power-domain handles would have to be added to devices that >>> potentially already have a power-domain handle, right? Isn't that going >>> to cause issues? I vaguely recall that we already have multiple power >>> domains for the XUSB controller and we have to jump through extra hoops >>> to make that work. >> >> I modeled the core PD as a parent of the PMC sub-domains, which >> presumably is a correct way to represent the domains topology. >> >> https://gist.github.com/digetx/dfd92c7f7e0aa6cef20403c4298088d7 >> >>>> The only thing which makes me feel a bit uncomfortable is that there is >>>> no real hardware node for the power domain node in a device-tree. >>> Could we anchor the new power domain at the PMC for example? That would >>> allow us to avoid the "virtual" node. >> >> I had a thought about using PMC for the core domain, but not sure >> whether it will be an entirely correct hardware description. Although, >> it will be nice to have it this way. >> >> This is what Tegra TRM says about PMC: >> >> "The Power Management Controller (PMC) block interacts with an external >> or Power Manager Unit (PMU). The PMC mostly controls the entry and exit >> of the system from different sleep modes. It provides power-gating >> controllers for SOC and CPU power-islands and also provides scratch >> storage to save some of the context during sleep modes (when CPU and/or >> SOC power rails are off). Additionally, PMC interacts with the external >> Power Manager Unit (PMU)." >> >> The core voltage regulator is a part of the PMU. >> >> Not all core SoC devices are behind PMC, IIUC. > > There are usually some SoC devices that are always-on. Things like the > RTC for example, can never be power-gated, as far as I recall. On newer > chips there are usually many more blocks that can't be powergated at > all. The RTC is actually a special power domain on Tegra, it's not a part of the CORE domain, they are separate from each other. We need to know what blocks belong to a power domain and what's the power topology of these blocks. I think we already have this knowledge, so it shouldn't be a problem. >>> On the other hand, if we were to >>> use a regulator, we'd be adding a node for that, right? So isn't this >>> effectively going to be the same node if we use a power domain? Both >>> software constructs are using the same voltage regulator, so they should >>> be able to be described by the same device tree node, shouldn't they? >> >> I'm not exactly sure what you're meaning by "use a regulator" and "we'd >> be adding a node for that", could you please clarify? This v1 approach >> uses a core-supply phandle (i.e. regulator is used), it doesn't require >> extra nodes. > > What I meant to say was that the actual supply voltage is generated by > some device (typically one of the SD outputs of the PMIC). Whether we > model this as a power domain or a regulator doesn't really matter, > right? So I'm wondering if the device that generates the voltage should > be the power domain provider, just like it is the provider of the > regulator if this was modelled as a regulator. Technically this could be done and it shouldn't be difficult to add GENPD support to the regulator framework, but I think this is an inaccurate hardware description. It shouldn't be correct to describe internal SoC parts as directly-connected to an external voltage regulator. The core voltage regulator is connected to a one of several power rails of the Tegra chip. There is no good way to describe hardware in terms of voltage regulators, hence that's why this v1 series added a core-supply to each SoC component of each board's DT individually. It's actually one of the benefits of using a separate DT node for the power-domain, which describes the "Tegra Core" part of the Tegra SoC, and thus, it all stays within tegra.dtsi. This means that PD explicitly belongs to the SoC internals in oppose to describing PD like it's an external/off-chip component. Initially I didn't like much that there is no hardware address to back up the power domain node in a DT, but actually there is no address for the power rail. Hence it should be better to describe hardware by keeping PD internally to the SoC. Note that potentially PD may require knowledge about specifics of a particular SoC, while external regulator doesn't belong to a SoC. Also, I guess technically there could be multiple external regulators which power a single SoC rail. From krzk at kernel.org Sun Nov 15 17:09:47 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Sun, 15 Nov 2020 18:09:47 +0100 Subject: [PATCH 0/3] clk/sunxi/media: Fix builds with COMMON_CLK and HAVE_LEGACY_CLK Message-ID: <20201115170950.304460-1-krzk@kernel.org> Hi, Multiple configurations create unbuildable config by selecting COMMON_CLK and HAVE_LEGACY_CLK. The first simply should not be selected. The patches 2/3 and 3/3 address this specific problem. I performed few compile tests and I am still building other configurations, therefore they were marked as RFC. Best regards, Krzysztof Krzysztof Kozlowski (3): clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK ARM: sunxi: do not select COMMON_CLK to fix builds media: atomisp: do not select COMMON_CLK to fix builds arch/arm/mach-sunxi/Kconfig | 1 + drivers/clk/clk.c | 4 ++++ drivers/staging/media/atomisp/Kconfig | 2 +- sound/soc/sunxi/Kconfig | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) -- 2.25.1 From krzk at kernel.org Sun Nov 15 17:09:48 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Sun, 15 Nov 2020 18:09:48 +0100 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <20201115170950.304460-1-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> Message-ID: <20201115170950.304460-2-krzk@kernel.org> COMMON_CLK even though is a user-selectable symbol, is still selected by multiple other config options. COMMON_CLK should not be used when legacy clocks are provided by architecture, so it correctly depends on !HAVE_LEGACY_CLK. However it is possible to create a config which selects both COMMON_CLK (by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (by SOC_RT305X) which leads to compile errors (MIPS architecture): drivers/clk/clk.c:855:6: error: redefinition of ?clk_unprepare? In file included from drivers/clk/clk.c:9: include/linux/clk.h:263:20: note: previous definition of ?clk_unprepare? was here The definitions clk_bulk_prepare() (and unprepare) already have proper surrounding #ifdef so add them also for clk_prepare()/clk_unprepare(). Signed-off-by: Krzysztof Kozlowski --- drivers/clk/clk.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f83dac54ed85..f4f68c7c2fb5 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -841,6 +841,7 @@ static void clk_core_unprepare_lock(struct clk_core *core) clk_prepare_unlock(); } +#ifdef CONFIG_HAVE_CLK_PREPARE /** * clk_unprepare - undo preparation of a clock source * @clk: the clk being unprepared @@ -860,6 +861,7 @@ void clk_unprepare(struct clk *clk) clk_core_unprepare_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_unprepare); +#endif static int clk_core_prepare(struct clk_core *core) { @@ -921,6 +923,7 @@ static int clk_core_prepare_lock(struct clk_core *core) return ret; } +#ifdef CONFIG_HAVE_CLK_PREPARE /** * clk_prepare - prepare a clock source * @clk: the clk being prepared @@ -941,6 +944,7 @@ int clk_prepare(struct clk *clk) return clk_core_prepare_lock(clk->core); } EXPORT_SYMBOL_GPL(clk_prepare); +#endif /* CONFIG_HAVE_CLK_PREPARE */ static void clk_core_disable(struct clk_core *core) { -- 2.25.1 From krzk at kernel.org Sun Nov 15 17:09:49 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Sun, 15 Nov 2020 18:09:49 +0100 Subject: [RFC 2/3] ARM: sunxi: do not select COMMON_CLK to fix builds In-Reply-To: <20201115170950.304460-1-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> Message-ID: <20201115170950.304460-3-krzk@kernel.org> COMMON_CLK is a user-selectable option with its own dependencies. The most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers should not select COMMON_CLK because they will create a dependency cycle and build failures. For example on MIPS a configuration with COMMON_CLK (selected by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (selected by SOC_RT305X) is possible: WARNING: unmet direct dependencies detected for COMMON_CLK Depends on [n]: !HAVE_LEGACY_CLK [=y] Selected by [y]: - SND_SUN8I_CODEC [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && (ARCH_SUNXI || COMPILE_TEST [=y]) && OF [=y] && (MACH_SUN8I || ARM64 && ARCH_SUNXI || COMPILE_TEST [=y]) /usr/bin/mips-linux-gnu-ld: drivers/clk/clk.o: in function `clk_set_rate': (.text+0xaeb4): multiple definition of `clk_set_rate'; arch/mips/ralink/clk.o:(.text+0x88): first defined here Signed-off-by: Krzysztof Kozlowski --- arch/arm/mach-sunxi/Kconfig | 1 + sound/soc/sunxi/Kconfig | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig index eeadb1a4dcfe..4d9f9b6d329d 100644 --- a/arch/arm/mach-sunxi/Kconfig +++ b/arch/arm/mach-sunxi/Kconfig @@ -4,6 +4,7 @@ menuconfig ARCH_SUNXI depends on ARCH_MULTI_V5 || ARCH_MULTI_V7 select ARCH_HAS_RESET_CONTROLLER select CLKSRC_MMIO + select COMMON_CLK select GENERIC_IRQ_CHIP select GPIOLIB select PINCTRL diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index 69b9d8515335..ddcaaa98d3cb 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -14,7 +14,7 @@ config SND_SUN8I_CODEC tristate "Allwinner SUN8I audio codec" depends on OF depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST - select COMMON_CLK + depends on COMMON_CLK select REGMAP_MMIO help This option enables the digital part of the internal audio codec for -- 2.25.1 From krzk at kernel.org Sun Nov 15 17:09:50 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Sun, 15 Nov 2020 18:09:50 +0100 Subject: [RFC 3/3] media: atomisp: do not select COMMON_CLK to fix builds In-Reply-To: <20201115170950.304460-1-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> Message-ID: <20201115170950.304460-4-krzk@kernel.org> COMMON_CLK is a user-selectable option with its own dependencies. The most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers should not select COMMON_CLK because they will create a dependency cycle and build failures. Signed-off-by: Krzysztof Kozlowski --- drivers/staging/media/atomisp/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/atomisp/Kconfig b/drivers/staging/media/atomisp/Kconfig index 37577bb72998..742edb261d85 100644 --- a/drivers/staging/media/atomisp/Kconfig +++ b/drivers/staging/media/atomisp/Kconfig @@ -2,9 +2,9 @@ menuconfig INTEL_ATOMISP bool "Enable support to Intel Atom ISP camera drivers" depends on X86 && EFI && PCI && ACPI + depends on COMMON_CLK select IOSF_MBI select MEDIA_CONTROLLER - select COMMON_CLK help Enable support for the Intel ISP2 camera interfaces and MIPI sensor drivers. -- 2.25.1 From digetx at gmail.com Sun Nov 15 17:42:10 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Sun, 15 Nov 2020 20:42:10 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201113172859.GF4828@sirena.org.uk> References: <20201111115534.GA4847@sirena.org.uk> <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> <20201113172859.GF4828@sirena.org.uk> Message-ID: <74cfc6a9-3f59-d679-14b7-51102a6f11b3@gmail.com> 13.11.2020 20:28, Mark Brown ?????: > On Fri, Nov 13, 2020 at 08:13:49PM +0300, Dmitry Osipenko wrote: >> 13.11.2020 19:15, Mark Brown ?????: > >>> My point here is that the driver shouldn't be checking for a dummy >>> regulator, the driver should be checking the features that are provided >>> to it by the regulator and handling those. > >> I understand yours point, but then we need dummy regulator to provide >> all the features, and currently it does the opposite. > > As could any other regulator? Yes >>> It doesn't matter if this is >>> a dummy regulator or an actual regulator with limited features, the >>> effect is the same and the handling should be the same. If the driver >>> is doing anything to handle dummy regulators explicitly as dummy >>> regulators it is doing it wrong. > >> It matters because dummy regulator errors out all checks and changes >> other than enable/disable, instead of accepting them. If we could add an >> option for dummy regulator to succeed all the checks and accept all the >> values, then it could become more usable. > > I'm a bit confused here TBH - I'm not sure I see a substantial > difference between a consumer detecting that it can't set any voltages > at all and the handling for an optional regulator. Either way if it's > going to carry on and assume that whatever voltage is there works for > everything it boils down to setting a flag saying to skip the set > voltage operation. I think you are too focused on the specific > implementation you currently have here. > > We obviously can't just accept voltage change operations when we've no > idea what the current voltage of the device is. > >>> To repeat you should *only* be using regulator_get_optional() in the >>> case where the supply may be physically absent which is not the case >>> here. >> >> Alright, but then we either need to improve regulator core to make dummy >> regulator a bit more usable, or continue to work around it in drivers. >> What should we do? > > As I keep saying the consumer driver should be enumerating the voltages > it can set, if it can't find any and wants to continue then it can just > skip setting voltages later on. If only some are unavailable then it > probably wants to eliminate those specific OPPs instead. I'm seeing a dummy regulator as a helper for consumer drivers which removes burden of handling an absent (optional) regulator. Is this a correct understanding of a dummy regulator? Older DTBs don't have a regulator and we want to keep them working. This is equal to a physically absent regulator and in this case it's an optional regulator, IMO. Consumer drivers definitely should check voltages, but this should be done only for a physical regulator. From info at kshamadevigroup.com Sun Nov 15 14:20:59 2020 From: info at kshamadevigroup.com (Home of Mega Millions and Powerball) Date: Sun, 15 Nov 2020 06:20:59 -0800 Subject: Home of Mega Millions and Powerball Message-ID: <20201115181432.2644C86A8F@whitealder.osuosl.org> Dear Email Owner, Congratulation! Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. This Electronic E-mail notification is to remind you again that your email address has won you the sum of nine hundred and fifty thousand dollars ($950.000.00) from the ($165.000.000.00) Online MEGA MILLIONS POWERBALL LOTTERY. Email addresses were randomly collected from various region and domins and your email won the lucky number 23-45-53-58-62 + 13 in the Mega Million Powerball Lottery. In other to access the winning amount kindly contact our fudiciary agent for your online Payment Identification Number (Pin) that will enable you transfer your payment to your prefer bank account with your reference number: Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. Please quote your reference when contacting our Payment Agents. Blutter Bros. E-mail: contact at itpm-safi.ac.ma Congratulations. USA-UK Home of Mega Millions and Powerball, the USA's biggest multi-state lottery games. VUJKHVYILKDDDEXOGFJJTRTCQJHXNVHLSTVVBO From info at kshamadevigroup.com Sun Nov 15 14:20:59 2020 From: info at kshamadevigroup.com (Home of Mega Millions and Powerball) Date: Sun, 15 Nov 2020 06:20:59 -0800 Subject: Home of Mega Millions and Powerball Message-ID: <20201115181433.729CF868F6@whitealder.osuosl.org> Dear Email Owner, Congratulation! Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. This Electronic E-mail notification is to remind you again that your email address has won you the sum of nine hundred and fifty thousand dollars ($950.000.00) from the ($165.000.000.00) Online MEGA MILLIONS POWERBALL LOTTERY. Email addresses were randomly collected from various region and domins and your email won the lucky number 23-45-53-58-62 + 13 in the Mega Million Powerball Lottery. In other to access the winning amount kindly contact our fudiciary agent for your online Payment Identification Number (Pin) that will enable you transfer your payment to your prefer bank account with your reference number: Ref: Mega-Powerball- 23-45-53-58-62 + 13/23/TPA. Please quote your reference when contacting our Payment Agents. Blutter Bros. E-mail: contact at itpm-safi.ac.ma Congratulations. USA-UK Home of Mega Millions and Powerball, the USA's biggest multi-state lottery games. VUJKHVYILKDDDEXOGFJJTRTCQJHXNVHLSTVVBO From martin at c-home.cz Sun Nov 15 18:59:24 2020 From: martin at c-home.cz (Martin Cerveny) Date: Sun, 15 Nov 2020 19:59:24 +0100 (CET) Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: References: <20200912143052.30952-1-m.cerveny@computer.org> Message-ID: Hello. On Thu, 5 Nov 2020, Hans Verkuil wrote: > Hi Martin, > > On 12/09/2020 16:30, Martin Cerveny wrote: >> First patch extends cedrus capability to all decoders >> because V3s missing MPEG2 decoder. >> >> Next two patches add system control node (SRAM C1) and >> next three patches add support for Cedrus VPU. >> >> Tested on "Lichee Zero" V3s platform with testing LCD patch >> ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) >> and V4L2 raw API testing utility >> ( https://github.com/mcerveny/v4l2-request-test ): >> - enabled LCD (DRM dual VI and sigle UI planes) >> - added RGB panel >> - enabled PWM >> >> There is low memory on V3s (64MB) and maximum must be available to CMA: >> - CONFIG_CMA_SIZE_MBYTES=28 >> - add swap to swapout other processes >> - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) >> >> Only H.264 decoder working - MPEG and H.265 unsupported by V3s, >> JPEG/MJPEG still unimplemented, encoder unimplemented > > When I tried to merged these patches I got merge conflicts. > > Possibly due to other 5.10 changes, but certainly because of conflicts > with patches from Jernej: > > https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ > https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ > > I've merged Jerne's patches and posted a PR for that: > https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ > > Can you rebase your patches on top of my branch that contains Jernej's patches? > > https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e > > Once my PR is merged into the media_tree master I can take your rebased > patches. I updated patches: https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e BUT, commit (555 commits) for v5.10-1 https://github.com/torvalds/linux/commit/fd5c32d80884268a381ed0e67cccef0b3d37750b disrupts usability of Cedrus H.264 (at least for my Allwinner V3s): 1) colors are disrupted There are missing some initialization now. If I use "5.9" compatible code (last bisect good point https://github.com/torvalds/linux/commit/647412daeb454b6dad12a6c6961ab90aac9e5d29 ) then reboot (not power-off!) and use new code ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) and colors are OK. 2) decoding of complex streams fails ( https://github.com/mcerveny/v4l2-request-test/tree/v5.10 ) - bbb-h264-all-i-32 - OK - bbb-h264-32 - bad from frame 5 - bbb-h264-high-32 - bad from frame 6 best regards, Martin >> Changes since v1: >> - patch 0005 rename >> - added testing description >> >> Martin Cerveny (6): >> media: cedrus: Register all codecs as capability >> dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s >> compatibles >> ARM: dts: sun8i: v3s: Add node for system control >> media: cedrus: Add support for V3s >> dt-bindings: media: cedrus: Add V3s compatible >> ARM: dts: sun8i: v3s: Add video engine node >> >> .../allwinner,sun4i-a10-video-engine.yaml | 1 + >> .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ >> arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ >> drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- >> drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ >> .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ >> 6 files changed, 71 insertions(+), 1 deletion(-) >> > From christianshewitt at gmail.com Mon Nov 16 04:30:55 2020 From: christianshewitt at gmail.com (Christian Hewitt) Date: Mon, 16 Nov 2020 04:30:55 +0000 Subject: [PATCH] media: meson: vdec: add G12/SM1 to module description Message-ID: <20201116043055.23655-1-christianshewitt@gmail.com> The meson vdec driver also supports Amlogic G12/SM1 hardware. Signed-off-by: Christian Hewitt --- drivers/staging/media/meson/vdec/vdec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c index 5ccb3846c879..5d4db7a5b4b5 100644 --- a/drivers/staging/media/meson/vdec/vdec.c +++ b/drivers/staging/media/meson/vdec/vdec.c @@ -1131,6 +1131,6 @@ static struct platform_driver meson_vdec_driver = { }; module_platform_driver(meson_vdec_driver); -MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); +MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM/G12/SM1"); MODULE_AUTHOR("Maxime Jourdan "); MODULE_LICENSE("GPL"); -- 2.17.1 From narmstrong at baylibre.com Mon Nov 16 08:35:23 2020 From: narmstrong at baylibre.com (Neil Armstrong) Date: Mon, 16 Nov 2020 09:35:23 +0100 Subject: [PATCH] media: meson: vdec: add G12/SM1 to module description In-Reply-To: <20201116043055.23655-1-christianshewitt@gmail.com> References: <20201116043055.23655-1-christianshewitt@gmail.com> Message-ID: On 16/11/2020 05:30, Christian Hewitt wrote: > The meson vdec driver also supports Amlogic G12/SM1 hardware. > > Signed-off-by: Christian Hewitt > --- > drivers/staging/media/meson/vdec/vdec.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/drivers/staging/media/meson/vdec/vdec.c b/drivers/staging/media/meson/vdec/vdec.c > index 5ccb3846c879..5d4db7a5b4b5 100644 > --- a/drivers/staging/media/meson/vdec/vdec.c > +++ b/drivers/staging/media/meson/vdec/vdec.c > @@ -1131,6 +1131,6 @@ static struct platform_driver meson_vdec_driver = { > }; > module_platform_driver(meson_vdec_driver); > > -MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM"); > +MODULE_DESCRIPTION("Meson video decoder driver for GXBB/GXL/GXM/G12/SM1"); > MODULE_AUTHOR("Maxime Jourdan "); > MODULE_LICENSE("GPL"); > Reviewed-by: Neil Armstrong From hverkuil at xs4all.nl Mon Nov 16 08:38:45 2020 From: hverkuil at xs4all.nl (Hans Verkuil) Date: Mon, 16 Nov 2020 09:38:45 +0100 Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: References: <20200912143052.30952-1-m.cerveny@computer.org> Message-ID: <19bbdf9f-3894-606b-728e-b41df27a4f5d@xs4all.nl> On 15/11/2020 19:59, Martin Cerveny wrote: > Hello. > > On Thu, 5 Nov 2020, Hans Verkuil wrote: > >> Hi Martin, >> >> On 12/09/2020 16:30, Martin Cerveny wrote: >>> First patch extends cedrus capability to all decoders >>> because V3s missing MPEG2 decoder. >>> >>> Next two patches add system control node (SRAM C1) and >>> next three patches add support for Cedrus VPU. >>> >>> Tested on "Lichee Zero" V3s platform with testing LCD patch >>> ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) >>> and V4L2 raw API testing utility >>> ( https://github.com/mcerveny/v4l2-request-test ): >>> - enabled LCD (DRM dual VI and sigle UI planes) >>> - added RGB panel >>> - enabled PWM >>> >>> There is low memory on V3s (64MB) and maximum must be available to CMA: >>> - CONFIG_CMA_SIZE_MBYTES=28 >>> - add swap to swapout other processes >>> - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) >>> >>> Only H.264 decoder working - MPEG and H.265 unsupported by V3s, >>> JPEG/MJPEG still unimplemented, encoder unimplemented >> >> When I tried to merged these patches I got merge conflicts. >> >> Possibly due to other 5.10 changes, but certainly because of conflicts >> with patches from Jernej: >> >> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ >> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ >> >> I've merged Jerne's patches and posted a PR for that: >> https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ >> >> Can you rebase your patches on top of my branch that contains Jernej's patches? >> >> https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e >> >> Once my PR is merged into the media_tree master I can take your rebased >> patches. > > I updated patches: > https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e > > BUT, commit (555 commits) for v5.10-1 > https://github.com/torvalds/linux/commit/fd5c32d80884268a381ed0e67cccef0b3d37750b > disrupts usability of Cedrus H.264 (at least for my Allwinner V3s): > > 1) colors are disrupted > > There are missing some initialization now. > > If I use "5.9" compatible code > (last bisect good point https://github.com/torvalds/linux/commit/647412daeb454b6dad12a6c6961ab90aac9e5d29 ) > then reboot (not power-off!) and use new code > ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) > and colors are OK. Could this or the next issue be related to this bug fix? https://git.linuxtv.org/media_tree.git/commit/?h=fixes&id=9ac924b98728c3733c91c6c59fc410827d0da49f That fix isn't yet in our master tree. > > 2) decoding of complex streams fails > > ( https://github.com/mcerveny/v4l2-request-test/tree/v5.10 ) > - bbb-h264-all-i-32 - OK > - bbb-h264-32 - bad from frame 5 > - bbb-h264-high-32 - bad from frame 6 I think cedrus devs need to take a look at these issues. Regards, Hans > > best regards, > Martin > >>> Changes since v1: >>> - patch 0005 rename >>> - added testing description >>> >>> Martin Cerveny (6): >>> media: cedrus: Register all codecs as capability >>> dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s >>> compatibles >>> ARM: dts: sun8i: v3s: Add node for system control >>> media: cedrus: Add support for V3s >>> dt-bindings: media: cedrus: Add V3s compatible >>> ARM: dts: sun8i: v3s: Add video engine node >>> >>> .../allwinner,sun4i-a10-video-engine.yaml | 1 + >>> .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ >>> arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ >>> drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- >>> drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ >>> .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ >>> 6 files changed, 71 insertions(+), 1 deletion(-) >>> >> From martin at c-home.cz Mon Nov 16 09:37:39 2020 From: martin at c-home.cz (Martin Cerveny) Date: Mon, 16 Nov 2020 10:37:39 +0100 (CET) Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: <19bbdf9f-3894-606b-728e-b41df27a4f5d@xs4all.nl> References: <20200912143052.30952-1-m.cerveny@computer.org> <19bbdf9f-3894-606b-728e-b41df27a4f5d@xs4all.nl> Message-ID: On Mon, 16 Nov 2020, Hans Verkuil wrote: > On 15/11/2020 19:59, Martin Cerveny wrote: >> Hello. >> >> On Thu, 5 Nov 2020, Hans Verkuil wrote: >> >>> Hi Martin, >>> >>> On 12/09/2020 16:30, Martin Cerveny wrote: >>>> First patch extends cedrus capability to all decoders >>>> because V3s missing MPEG2 decoder. >>>> >>>> Next two patches add system control node (SRAM C1) and >>>> next three patches add support for Cedrus VPU. >>>> >>>> Tested on "Lichee Zero" V3s platform with testing LCD patch >>>> ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) >>>> and V4L2 raw API testing utility >>>> ( https://github.com/mcerveny/v4l2-request-test ): >>>> - enabled LCD (DRM dual VI and sigle UI planes) >>>> - added RGB panel >>>> - enabled PWM >>>> >>>> There is low memory on V3s (64MB) and maximum must be available to CMA: >>>> - CONFIG_CMA_SIZE_MBYTES=28 >>>> - add swap to swapout other processes >>>> - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) >>>> >>>> Only H.264 decoder working - MPEG and H.265 unsupported by V3s, >>>> JPEG/MJPEG still unimplemented, encoder unimplemented >>> >>> When I tried to merged these patches I got merge conflicts. >>> >>> Possibly due to other 5.10 changes, but certainly because of conflicts >>> with patches from Jernej: >>> >>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ >>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ >>> >>> I've merged Jerne's patches and posted a PR for that: >>> https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ >>> >>> Can you rebase your patches on top of my branch that contains Jernej's patches? >>> >>> https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e >>> >>> Once my PR is merged into the media_tree master I can take your rebased >>> patches. >> >> I updated patches: >> https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e >> >> BUT, commit (555 commits) for v5.10-1 >> https://github.com/torvalds/linux/commit/fd5c32d80884268a381ed0e67cccef0b3d37750b >> disrupts usability of Cedrus H.264 (at least for my Allwinner V3s): >> >> 1) colors are disrupted >> >> There are missing some initialization now. >> >> If I use "5.9" compatible code >> (last bisect good point https://github.com/torvalds/linux/commit/647412daeb454b6dad12a6c6961ab90aac9e5d29 ) >> then reboot (not power-off!) and use new code >> ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) >> and colors are OK. > > Could this or the next issue be related to this bug fix? > > https://git.linuxtv.org/media_tree.git/commit/?h=fixes&id=9ac924b98728c3733c91c6c59fc410827d0da49f > > That fix isn't yet in our master tree. Confirmed. It recovers colors ! >> >> 2) decoding of complex streams fails >> >> ( https://github.com/mcerveny/v4l2-request-test/tree/v5.10 ) >> - bbb-h264-all-i-32 - OK >> - bbb-h264-32 - bad from frame 5 >> - bbb-h264-high-32 - bad from frame 6 > > I think cedrus devs need to take a look at these issues. Maybe something wrong in my testing code, problematic commit swapped some variables between structures :-( I try to investigate more, regards Martin > Regards, > > Hans > >> >> best regards, >> Martin >> >>>> Changes since v1: >>>> - patch 0005 rename >>>> - added testing description >>>> >>>> Martin Cerveny (6): >>>> media: cedrus: Register all codecs as capability >>>> dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s >>>> compatibles >>>> ARM: dts: sun8i: v3s: Add node for system control >>>> media: cedrus: Add support for V3s >>>> dt-bindings: media: cedrus: Add V3s compatible >>>> ARM: dts: sun8i: v3s: Add video engine node >>>> >>>> .../allwinner,sun4i-a10-video-engine.yaml | 1 + >>>> .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ >>>> arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ >>>> drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- >>>> drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ >>>> .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ >>>> 6 files changed, 71 insertions(+), 1 deletion(-) >>>> >>> > From martin at c-home.cz Mon Nov 16 12:07:27 2020 From: martin at c-home.cz (Martin Cerveny) Date: Mon, 16 Nov 2020 13:07:27 +0100 (CET) Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: References: <20200912143052.30952-1-m.cerveny@computer.org> <19bbdf9f-3894-606b-728e-b41df27a4f5d@xs4all.nl> Message-ID: Hello. On Mon, 16 Nov 2020, Martin Cerveny wrote: > On Mon, 16 Nov 2020, Hans Verkuil wrote: >> On 15/11/2020 19:59, Martin Cerveny wrote: >>> On Thu, 5 Nov 2020, Hans Verkuil wrote: >>>> On 12/09/2020 16:30, Martin Cerveny wrote: >>>>> First patch extends cedrus capability to all decoders >>>>> because V3s missing MPEG2 decoder. >>>>> >>>>> Next two patches add system control node (SRAM C1) and >>>>> next three patches add support for Cedrus VPU. >>>>> >>>>> Tested on "Lichee Zero" V3s platform with testing LCD patch >>>>> ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) >>>>> and V4L2 raw API testing utility >>>>> ( https://github.com/mcerveny/v4l2-request-test ): >>>>> - enabled LCD (DRM dual VI and sigle UI planes) >>>>> - added RGB panel >>>>> - enabled PWM >>>>> >>>>> There is low memory on V3s (64MB) and maximum must be available to CMA: >>>>> - CONFIG_CMA_SIZE_MBYTES=28 >>>>> - add swap to swapout other processes >>>>> - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) >>>>> >>>>> Only H.264 decoder working - MPEG and H.265 unsupported by V3s, >>>>> JPEG/MJPEG still unimplemented, encoder unimplemented >>>> >>>> When I tried to merged these patches I got merge conflicts. >>>> >>>> Possibly due to other 5.10 changes, but certainly because of conflicts >>>> with patches from Jernej: >>>> >>>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ >>>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ >>>> >>>> I've merged Jerne's patches and posted a PR for that: >>>> https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ >>>> >>>> Can you rebase your patches on top of my branch that contains Jernej's >>>> patches? >>>> >>>> https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e >>>> >>>> Once my PR is merged into the media_tree master I can take your rebased >>>> patches. >>> >>> I updated patches: >>> https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e >>> >>> BUT, commit (555 commits) for v5.10-1 >>> https://github.com/torvalds/linux/commit/fd5c32d80884268a381ed0e67cccef0b3d37750b >>> disrupts usability of Cedrus H.264 (at least for my Allwinner V3s): >>> >>> 1) colors are disrupted >>> >>> There are missing some initialization now. >>> >>> If I use "5.9" compatible code >>> (last bisect good point >>> https://github.com/torvalds/linux/commit/647412daeb454b6dad12a6c6961ab90aac9e5d29 >>> ) >>> then reboot (not power-off!) and use new code >>> ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) >>> and colors are OK. >> >> Could this or the next issue be related to this bug fix? >> >> https://git.linuxtv.org/media_tree.git/commit/?h=fixes&id=9ac924b98728c3733c91c6c59fc410827d0da49f >> >> That fix isn't yet in our master tree. > > Confirmed. It recovers colors ! > >>> >>> 2) decoding of complex streams fails >>> >>> ( https://github.com/mcerveny/v4l2-request-test/tree/v5.10 ) >>> - bbb-h264-all-i-32 - OK >>> - bbb-h264-32 - bad from frame 5 >>> - bbb-h264-high-32 - bad from frame 6 >> >> I think cedrus devs need to take a look at these issues. > > Maybe something wrong in my testing code, > problematic commit swapped some variables between structures :-( > > I try to investigate more, regards Martin Yes. I found new format in ref_pic_list. I updated test application. All H.264 tests are working now. https://github.com/mcerveny/v4l2-request-test Is it necessary to release new "Patch V3" (rebased) series from https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e or not ? Regards, Martin >> Regards, >> >> Hans >> >>> >>> best regards, >>> Martin >>> >>>>> Changes since v1: >>>>> - patch 0005 rename >>>>> - added testing description >>>>> >>>>> Martin Cerveny (6): >>>>> media: cedrus: Register all codecs as capability >>>>> dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s >>>>> compatibles >>>>> ARM: dts: sun8i: v3s: Add node for system control >>>>> media: cedrus: Add support for V3s >>>>> dt-bindings: media: cedrus: Add V3s compatible >>>>> ARM: dts: sun8i: v3s: Add video engine node >>>>> >>>>> .../allwinner,sun4i-a10-video-engine.yaml | 1 + >>>>> .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ >>>>> arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ >>>>> drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- >>>>> drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ >>>>> .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ >>>>> 6 files changed, 71 insertions(+), 1 deletion(-) >>>>> >>>> >> > From hverkuil at xs4all.nl Mon Nov 16 12:18:42 2020 From: hverkuil at xs4all.nl (Hans Verkuil) Date: Mon, 16 Nov 2020 13:18:42 +0100 Subject: [PATCH v2 0/6] ARM: dts: sun8i: v3s: Enable video decoder In-Reply-To: References: <20200912143052.30952-1-m.cerveny@computer.org> <19bbdf9f-3894-606b-728e-b41df27a4f5d@xs4all.nl> Message-ID: <6219ea18-f4a5-ab75-85dd-1acdb9159ce9@xs4all.nl> On 16/11/2020 13:07, Martin Cerveny wrote: > Hello. > > On Mon, 16 Nov 2020, Martin Cerveny wrote: >> On Mon, 16 Nov 2020, Hans Verkuil wrote: >>> On 15/11/2020 19:59, Martin Cerveny wrote: >>>> On Thu, 5 Nov 2020, Hans Verkuil wrote: >>>>> On 12/09/2020 16:30, Martin Cerveny wrote: >>>>>> First patch extends cedrus capability to all decoders >>>>>> because V3s missing MPEG2 decoder. >>>>>> >>>>>> Next two patches add system control node (SRAM C1) and >>>>>> next three patches add support for Cedrus VPU. >>>>>> >>>>>> Tested on "Lichee Zero" V3s platform with testing LCD patch >>>>>> ( https://github.com/mcerveny/linux/tree/v3s_videocodec_v4 ) >>>>>> and V4L2 raw API testing utility >>>>>> ( https://github.com/mcerveny/v4l2-request-test ): >>>>>> - enabled LCD (DRM dual VI and sigle UI planes) >>>>>> - added RGB panel >>>>>> - enabled PWM >>>>>> >>>>>> There is low memory on V3s (64MB) and maximum must be available to CMA: >>>>>> - CONFIG_CMA_SIZE_MBYTES=28 >>>>>> - add swap to swapout other processes >>>>>> - decrease buffers in v4l2-request-test (.buffers_count from 16 to 6) >>>>>> >>>>>> Only H.264 decoder working - MPEG and H.265 unsupported by V3s, >>>>>> JPEG/MJPEG still unimplemented, encoder unimplemented >>>>> >>>>> When I tried to merged these patches I got merge conflicts. >>>>> >>>>> Possibly due to other 5.10 changes, but certainly because of conflicts >>>>> with patches from Jernej: >>>>> >>>>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-4-jernej.skrabec at siol.net/ >>>>> https://patchwork.linuxtv.org/project/linux-media/patch/20200825173523.1289379-5-jernej.skrabec at siol.net/ >>>>> >>>>> I've merged Jerne's patches and posted a PR for that: >>>>> https://patchwork.linuxtv.org/project/linux-media/patch/f3b8e5e2-5f0e-fb6f-e5b2-7f44f7e365e7 at xs4all.nl/ >>>>> >>>>> Can you rebase your patches on top of my branch that contains Jernej's >>>>> patches? >>>>> >>>>> https://git.linuxtv.org/hverkuil/media_tree.git/log/?h=for-v5.11e >>>>> >>>>> Once my PR is merged into the media_tree master I can take your rebased >>>>> patches. >>>> >>>> I updated patches: >>>> https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e >>>> >>>> BUT, commit (555 commits) for v5.10-1 >>>> https://github.com/torvalds/linux/commit/fd5c32d80884268a381ed0e67cccef0b3d37750b >>>> disrupts usability of Cedrus H.264 (at least for my Allwinner V3s): >>>> >>>> 1) colors are disrupted >>>> >>>> There are missing some initialization now. >>>> >>>> If I use "5.9" compatible code >>>> (last bisect good point >>>> https://github.com/torvalds/linux/commit/647412daeb454b6dad12a6c6961ab90aac9e5d29 >>>> ) >>>> then reboot (not power-off!) and use new code >>>> ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) >>>> and colors are OK. >>> >>> Could this or the next issue be related to this bug fix? >>> >>> https://git.linuxtv.org/media_tree.git/commit/?h=fixes&id=9ac924b98728c3733c91c6c59fc410827d0da49f >>> >>> That fix isn't yet in our master tree. >> >> Confirmed. It recovers colors ! >> >>>> >>>> 2) decoding of complex streams fails >>>> >>>> ( https://github.com/mcerveny/v4l2-request-test/tree/v5.10 ) >>>> - bbb-h264-all-i-32 - OK >>>> - bbb-h264-32 - bad from frame 5 >>>> - bbb-h264-high-32 - bad from frame 6 >>> >>> I think cedrus devs need to take a look at these issues. >> >> Maybe something wrong in my testing code, >> problematic commit swapped some variables between structures :-( >> >> I try to investigate more, regards Martin > > Yes. I found new format in ref_pic_list. > I updated test application. All H.264 tests are working now. > > https://github.com/mcerveny/v4l2-request-test > > Is it necessary to release new "Patch V3" (rebased) series from > https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e or not ? Yes, please! That would be much appreciated. Regards, Hans > > Regards, Martin > >>> Regards, >>> >>> Hans >>> >>>> >>>> best regards, >>>> Martin >>>> >>>>>> Changes since v1: >>>>>> - patch 0005 rename >>>>>> - added testing description >>>>>> >>>>>> Martin Cerveny (6): >>>>>> media: cedrus: Register all codecs as capability >>>>>> dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s >>>>>> compatibles >>>>>> ARM: dts: sun8i: v3s: Add node for system control >>>>>> media: cedrus: Add support for V3s >>>>>> dt-bindings: media: cedrus: Add V3s compatible >>>>>> ARM: dts: sun8i: v3s: Add video engine node >>>>>> >>>>>> .../allwinner,sun4i-a10-video-engine.yaml | 1 + >>>>>> .../allwinner,sun4i-a10-system-control.yaml | 6 ++++ >>>>>> arch/arm/boot/dts/sun8i-v3s.dtsi | 33 +++++++++++++++++++ >>>>>> drivers/staging/media/sunxi/cedrus/cedrus.c | 28 +++++++++++++++- >>>>>> drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ >>>>>> .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ >>>>>> 6 files changed, 71 insertions(+), 1 deletion(-) >>>>>> >>>>> >>> >> From mchehab+huawei at kernel.org Mon Nov 16 12:59:26 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Mon, 16 Nov 2020 13:59:26 +0100 Subject: [PATCH 0/8] Move Hikey 970 USB support out of staging and add DT Message-ID: This patch series finish addressing support for Hikey 970 USB. It moves the power management and USB3 drivers out of staging, adding the device tree changes required for USB3 to work on Hikey 970. Mauro Carvalho Chehab (8): phy: phy-hi3670-usb3: move driver from staging into phy spmi: hi6421-spmi-pmic: move driver from staging mfd: hi6421-spmi-pmic: move driver from staging regulator: hi6421v600-regulator: move it from staging arm64: dts: hisilicon: hi3670.dtsi: add I2C settings arm64: dts: hikey970-pinctrl.dtsi: add missing pinctrl settings dts: hisilicon: add support for USB3 on Hikey 970 dts: hisilicon: add support for the PMIC found on Hikey 970 .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 159 +++++ .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ .../spmi/hisilicon,hisi-spmi-controller.yaml | 62 ++ MAINTAINERS | 24 +- .../boot/dts/hisilicon/hi3670-hikey970.dts | 124 +++- arch/arm64/boot/dts/hisilicon/hi3670.dtsi | 135 ++++ .../boot/dts/hisilicon/hikey970-pinctrl.dtsi | 548 +++++++++++++- .../boot/dts/hisilicon/hikey970-pmic.dtsi | 197 +++++ drivers/mfd/Kconfig | 15 + drivers/mfd/Makefile | 1 + drivers/mfd/hi6421-spmi-pmic.c | 342 +++++++++ drivers/phy/hisilicon/Kconfig | 10 + drivers/phy/hisilicon/Makefile | 1 + drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/hi6421v600-regulator.c | 478 +++++++++++++ drivers/spmi/Kconfig | 9 + drivers/spmi/Makefile | 1 + drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++ drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/hikey9xx/Kconfig | 49 -- drivers/staging/hikey9xx/Makefile | 7 - drivers/staging/hikey9xx/TODO | 5 - drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 342 --------- .../staging/hikey9xx/hi6421v600-regulator.c | 478 ------------- .../staging/hikey9xx/hisi-spmi-controller.c | 358 ---------- .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 159 ----- .../hisilicon,hisi-spmi-controller.yaml | 62 -- drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- 32 files changed, 3183 insertions(+), 2240 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml create mode 100644 arch/arm64/boot/dts/hisilicon/hikey970-pmic.dtsi create mode 100644 drivers/mfd/hi6421-spmi-pmic.c create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c create mode 100644 drivers/regulator/hi6421v600-regulator.c create mode 100644 drivers/spmi/hisi-spmi-controller.c delete mode 100644 drivers/staging/hikey9xx/Kconfig delete mode 100644 drivers/staging/hikey9xx/Makefile delete mode 100644 drivers/staging/hikey9xx/TODO delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c delete mode 100644 drivers/staging/hikey9xx/hi6421v600-regulator.c delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml -- 2.28.0 From mchehab+huawei at kernel.org Mon Nov 16 12:59:29 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Mon, 16 Nov 2020 13:59:29 +0100 Subject: [PATCH 3/8] mfd: hi6421-spmi-pmic: move driver from staging In-Reply-To: References: Message-ID: <504469db0d6659fdaed550a89822be6e7b8dc85e.1605530560.git.mchehab+huawei@kernel.org> This driver is ready for mainstream. So, move it out of staging. Signed-off-by: Mauro Carvalho Chehab --- .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 159 ++++++++ MAINTAINERS | 7 + drivers/mfd/Kconfig | 15 + drivers/mfd/Makefile | 1 + drivers/mfd/hi6421-spmi-pmic.c | 342 ++++++++++++++++++ drivers/staging/hikey9xx/Kconfig | 16 - drivers/staging/hikey9xx/Makefile | 1 - drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 342 ------------------ .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 159 -------- 9 files changed, 524 insertions(+), 518 deletions(-) create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml create mode 100644 drivers/mfd/hi6421-spmi-pmic.c delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml diff --git a/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml new file mode 100644 index 000000000000..80e74c261e05 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml @@ -0,0 +1,159 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon 6421v600 SPMI PMIC + +maintainers: + - Mauro Carvalho Chehab + +description: | + HiSilicon 6421v600 should be connected inside a MIPI System Power Management + (SPMI) bus. It provides interrupts and power supply. + + The GPIO and interrupt settings are represented as part of the top-level PMIC + node. + + The SPMI controller part is provided by + drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml. + +properties: + $nodename: + pattern: "pmic@[0-9a-f]" + + compatible: + const: hisilicon,hi6421v600-spmi + + reg: + maxItems: 1 + + '#interrupt-cells': + const: 2 + + interrupt-controller: + description: + Identify that the PMIC is capable of behaving as an interrupt controller. + + gpios: + maxItems: 1 + + regulators: + type: object + + properties: + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + patternProperties: + '^ldo[0-9]+@[0-9a-f]$': + type: object + + $ref: "/schemas/regulator/regulator.yaml#" + + properties: + reg: + description: Enable register. + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + + vsel-reg: + description: Voltage selector register. + + enable-mask: + description: Bitmask used to enable the regulator. + + voltage-table: + description: Table with the selector items for the voltage regulator. + minItems: 2 + maxItems: 16 + + off-on-delay-us: + description: Time required for changing state to enabled in microseconds. + + startup-delay-us: + description: Startup time in microseconds. + + idle-mode-mask: + description: Bitmask used to put the regulator on idle mode. + + eco-microamp: + description: Maximum current while on idle mode. + + required: + - reg + - vsel-reg + - enable-mask + - voltage-table + - off-on-delay-us + - startup-delay-us + +required: + - compatible + - reg + - regulators + +examples: + - | + /* pmic properties */ + + pmic: pmic at 0 { + compatible = "hisilicon,hi6421-spmi"; + reg = <0 0>; + + #interrupt-cells = <2>; + interrupt-controller; + gpios = <&gpio28 0 0>; + + regulators { + #address-cells = <1>; + #size-cells = <0>; + + ldo3: ldo3 at 16 { + reg = <0x16>; + vsel-reg = <0x51>; + + regulator-name = "ldo3"; + regulator-min-microvolt = <1500000>; + regulator-max-microvolt = <2000000>; + regulator-boot-on; + + enable-mask = <0x01>; + + voltage-table = <1500000>, <1550000>, <1600000>, <1650000>, + <1700000>, <1725000>, <1750000>, <1775000>, + <1800000>, <1825000>, <1850000>, <1875000>, + <1900000>, <1925000>, <1950000>, <2000000>; + off-on-delay-us = <20000>; + startup-delay-us = <120>; + }; + + ldo4: ldo4 at 17 { /* 40 PIN */ + reg = <0x17>; + vsel-reg = <0x52>; + + regulator-name = "ldo4"; + regulator-min-microvolt = <1725000>; + regulator-max-microvolt = <1900000>; + regulator-boot-on; + + enable-mask = <0x01>; + idle-mode-mask = <0x10>; + eco-microamp = <10000>; + + hi6421-vsel = <0x52 0x07>; + voltage-table = <1725000>, <1750000>, <1775000>, <1800000>, + <1825000>, <1850000>, <1875000>, <1900000>; + off-on-delay-us = <20000>; + startup-delay-us = <120>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 14bc7b45ed50..450c7cbc6725 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7994,6 +7994,13 @@ S: Maintained F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml F: drivers/spmi/hisi-spmi-controller.c +HISILICON SPMI PMIC DRIVER FOR HIKEY 6421v600 +M: Mauro Carvalho Chehab +L: linux-kernel at vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml +F: drivers/mfd/hi6421-spmi-pmic.c + HISILICON STAGING DRIVERS FOR HIKEY 960/970 M: Mauro Carvalho Chehab L: devel at driverdev.osuosl.org diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 8b99a13669bf..c04c2f6be1d9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -509,6 +509,21 @@ config MFD_HI6421_PMIC menus in order to enable them. We communicate with the Hi6421 via memory-mapped I/O. +config MFD_HI6421_SPMI + tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC" + depends on OF + depends on SPMI + select MFD_CORE + help + Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes + multi-functions, such as regulators, RTC, codec, Coulomb counter, + etc. + + This driver includes core APIs _only_. You have to select + individual components like voltage regulators under corresponding + menus in order to enable them. + We communicate with the Hi6421v600 via a SPMI bus. + config MFD_HI655X_PMIC tristate "HiSilicon Hi655X series PMU/Codec IC" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 1780019d2474..7744993c42bc 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -233,6 +233,7 @@ obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o obj-$(CONFIG_MFD_IQS62X) += iqs62x.o obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o +obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o obj-$(CONFIG_MFD_DLN2) += dln2.o obj-$(CONFIG_MFD_RT5033) += rt5033.o diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c new file mode 100644 index 000000000000..64b30d263c8d --- /dev/null +++ b/drivers/mfd/hi6421-spmi-pmic.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device driver for regulators in HISI PMIC IC + * + * Copyright (c) 2013 Linaro Ltd. + * Copyright (c) 2011 Hisilicon. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 8-bit register offset in PMIC */ +#define HISI_MASK_STATE 0xff + +#define HISI_IRQ_ARRAY 2 +#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8) + +#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202 +#define SOC_PMIC_IRQ0_ADDR 0x0212 + +#define HISI_IRQ_KEY_NUM 0 +#define HISI_IRQ_KEY_VALUE 0xc0 +#define HISI_IRQ_KEY_DOWN 7 +#define HISI_IRQ_KEY_UP 6 + +#define HISI_MASK_FIELD 0xFF +#define HISI_BITS 8 + +/*define the first group interrupt register number*/ +#define HISI_PMIC_FIRST_GROUP_INT_NUM 2 + +static const struct mfd_cell hi6421v600_devs[] = { + { .name = "hi6421v600-regulator", }, +}; + +/* + * The PMIC register is only 8-bit. + * Hisilicon SoC use hardware to map PMIC register into SoC mapping. + * At here, we are accessing SoC register with 32-bit. + */ +int hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg) +{ + struct spmi_device *pdev; + u8 read_value = 0; + u32 ret; + + pdev = to_spmi_device(pmic->dev); + if (!pdev) { + pr_err("%s: pdev get failed!\n", __func__); + return -ENODEV; + } + + ret = spmi_ext_register_readl(pdev, reg, &read_value, 1); + if (ret) { + pr_err("%s: spmi_ext_register_readl failed!\n", __func__); + return ret; + } + return read_value; +} +EXPORT_SYMBOL(hi6421_spmi_pmic_read); + +int hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val) +{ + struct spmi_device *pdev; + u32 ret; + + pdev = to_spmi_device(pmic->dev); + if (!pdev) { + pr_err("%s: pdev get failed!\n", __func__); + return -ENODEV; + } + + ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1); + if (ret) + pr_err("%s: spmi_ext_register_writel failed!\n", __func__); + + return ret; +} +EXPORT_SYMBOL(hi6421_spmi_pmic_write); + +int hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg, + u32 mask, u32 bits) +{ + unsigned long flags; + u32 data; + int ret; + + spin_lock_irqsave(&pmic->lock, flags); + data = hi6421_spmi_pmic_read(pmic, reg) & ~mask; + data |= mask & bits; + ret = hi6421_spmi_pmic_write(pmic, reg, data); + spin_unlock_irqrestore(&pmic->lock, flags); + + return ret; +} +EXPORT_SYMBOL(hi6421_spmi_pmic_rmw); + +static irqreturn_t hi6421_spmi_irq_handler(int irq, void *data) +{ + struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)data; + unsigned long pending; + int i, offset; + + for (i = 0; i < HISI_IRQ_ARRAY; i++) { + pending = hi6421_spmi_pmic_read(pmic, (i + SOC_PMIC_IRQ0_ADDR)); + pending &= HISI_MASK_FIELD; + if (pending != 0) + pr_debug("pending[%d]=0x%lx\n\r", i, pending); + + hi6421_spmi_pmic_write(pmic, (i + SOC_PMIC_IRQ0_ADDR), pending); + + /* solve powerkey order */ + if ((i == HISI_IRQ_KEY_NUM) && + ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) { + generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_DOWN]); + generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_UP]); + pending &= (~HISI_IRQ_KEY_VALUE); + } + + if (pending) { + for_each_set_bit(offset, &pending, HISI_BITS) + generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]); + } + } + + return IRQ_HANDLED; +} + +static void hi6421_spmi_irq_mask(struct irq_data *d) +{ + struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d); + u32 data, offset; + unsigned long flags; + + offset = (irqd_to_hwirq(d) >> 3); + offset += SOC_PMIC_IRQ_MASK_0_ADDR; + + spin_lock_irqsave(&pmic->lock, flags); + data = hi6421_spmi_pmic_read(pmic, offset); + data |= (1 << (irqd_to_hwirq(d) & 0x07)); + hi6421_spmi_pmic_write(pmic, offset, data); + spin_unlock_irqrestore(&pmic->lock, flags); +} + +static void hi6421_spmi_irq_unmask(struct irq_data *d) +{ + struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d); + u32 data, offset; + unsigned long flags; + + offset = (irqd_to_hwirq(d) >> 3); + offset += SOC_PMIC_IRQ_MASK_0_ADDR; + + spin_lock_irqsave(&pmic->lock, flags); + data = hi6421_spmi_pmic_read(pmic, offset); + data &= ~(1 << (irqd_to_hwirq(d) & 0x07)); + hi6421_spmi_pmic_write(pmic, offset, data); + spin_unlock_irqrestore(&pmic->lock, flags); +} + +static struct irq_chip hi6421_spmi_pmu_irqchip = { + .name = "hisi-irq", + .irq_mask = hi6421_spmi_irq_mask, + .irq_unmask = hi6421_spmi_irq_unmask, + .irq_disable = hi6421_spmi_irq_mask, + .irq_enable = hi6421_spmi_irq_unmask, +}; + +static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hw) +{ + struct hi6421_spmi_pmic *pmic = d->host_data; + + irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip, + handle_simple_irq, "hisi"); + irq_set_chip_data(virq, pmic); + irq_set_irq_type(virq, IRQ_TYPE_NONE); + + return 0; +} + +static const struct irq_domain_ops hi6421_spmi_domain_ops = { + .map = hi6421_spmi_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic) +{ + int i, pending; + + for (i = 0 ; i < HISI_IRQ_ARRAY; i++) + hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ_MASK_0_ADDR + i, + HISI_MASK_STATE); + + for (i = 0 ; i < HISI_IRQ_ARRAY; i++) { + pending = hi6421_spmi_pmic_read(pmic, SOC_PMIC_IRQ0_ADDR + i); + + pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n", + SOC_PMIC_IRQ0_ADDR + i, pending); + hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ0_ADDR + i, + HISI_MASK_STATE); + } +} + +static int hi6421_spmi_pmic_probe(struct spmi_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct hi6421_spmi_pmic *pmic; + unsigned int virq; + int ret, i; + + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); + if (!pmic) + return -ENOMEM; + + spin_lock_init(&pmic->lock); + + pmic->dev = dev; + + pmic->gpio = of_get_gpio(np, 0); + if (pmic->gpio < 0) + return pmic->gpio; + + if (!gpio_is_valid(pmic->gpio)) + return -EINVAL; + + ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic"); + if (ret < 0) { + dev_err(dev, "failed to request gpio%d\n", pmic->gpio); + return ret; + } + + pmic->irq = gpio_to_irq(pmic->gpio); + + hi6421_spmi_pmic_irq_prc(pmic); + + pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL); + if (!pmic->irqs) + goto irq_malloc; + + pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0, + &hi6421_spmi_domain_ops, pmic); + if (!pmic->domain) { + dev_err(dev, "failed irq domain add simple!\n"); + ret = -ENODEV; + goto irq_malloc; + } + + for (i = 0; i < HISI_IRQ_NUM; i++) { + virq = irq_create_mapping(pmic->domain, i); + if (!virq) { + dev_err(dev, "Failed mapping hwirq\n"); + ret = -ENOSPC; + goto irq_malloc; + } + pmic->irqs[i] = virq; + dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n", + __func__, i, pmic->irqs[i]); + } + + ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL, + IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND, + "pmic", pmic); + if (ret < 0) { + dev_err(dev, "could not claim pmic IRQ: error %d\n", ret); + goto irq_malloc; + } + + dev_set_drvdata(&pdev->dev, pmic); + + /* + * The logic below will rely that the pmic is already stored at + * drvdata. + */ + dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n", + pdev->dev.of_node); + ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, + hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs), + NULL, 0, NULL); + if (!ret) + return 0; + + dev_err(dev, "Failed to add child devices: %d\n", ret); + +irq_malloc: + free_irq(pmic->irq, pmic); + + return ret; +} + +static void hi6421_spmi_pmic_remove(struct spmi_device *pdev) +{ + struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev); + + free_irq(pmic->irq, pmic); +} + +static const struct of_device_id pmic_spmi_id_table[] = { + { .compatible = "hisilicon,hi6421-spmi" }, + { } +}; +MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); + +static struct spmi_driver hi6421_spmi_pmic_driver = { + .driver = { + .name = "hi6421-spmi-pmic", + .of_match_table = pmic_spmi_id_table, + }, + .probe = hi6421_spmi_pmic_probe, + .remove = hi6421_spmi_pmic_remove, +}; +module_spmi_driver(hi6421_spmi_pmic_driver); + +MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index 69392e42cd0d..1afb8648a2c4 100644 --- a/drivers/staging/hikey9xx/Kconfig +++ b/drivers/staging/hikey9xx/Kconfig @@ -1,21 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -# to be placed at drivers/mfd -config MFD_HI6421_SPMI - tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC" - depends on OF - depends on SPMI - select MFD_CORE - help - Add support for HiSilicon Hi6421v600 SPMI PMIC. Hi6421 includes - multi-functions, such as regulators, RTC, codec, Coulomb counter, - etc. - - This driver includes core APIs _only_. You have to select - individual components like voltage regulators under corresponding - menus in order to enable them. - We communicate with the Hi6421v600 via a SPMI bus. - # to be placed at drivers/regulator config REGULATOR_HI6421V600 tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile index 347880fd378f..4d63184e6086 100644 --- a/drivers/staging/hikey9xx/Makefile +++ b/drivers/staging/hikey9xx/Makefile @@ -1,4 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c deleted file mode 100644 index 64b30d263c8d..000000000000 --- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c +++ /dev/null @@ -1,342 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Device driver for regulators in HISI PMIC IC - * - * Copyright (c) 2013 Linaro Ltd. - * Copyright (c) 2011 Hisilicon. - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 8-bit register offset in PMIC */ -#define HISI_MASK_STATE 0xff - -#define HISI_IRQ_ARRAY 2 -#define HISI_IRQ_NUM (HISI_IRQ_ARRAY * 8) - -#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202 -#define SOC_PMIC_IRQ0_ADDR 0x0212 - -#define HISI_IRQ_KEY_NUM 0 -#define HISI_IRQ_KEY_VALUE 0xc0 -#define HISI_IRQ_KEY_DOWN 7 -#define HISI_IRQ_KEY_UP 6 - -#define HISI_MASK_FIELD 0xFF -#define HISI_BITS 8 - -/*define the first group interrupt register number*/ -#define HISI_PMIC_FIRST_GROUP_INT_NUM 2 - -static const struct mfd_cell hi6421v600_devs[] = { - { .name = "hi6421v600-regulator", }, -}; - -/* - * The PMIC register is only 8-bit. - * Hisilicon SoC use hardware to map PMIC register into SoC mapping. - * At here, we are accessing SoC register with 32-bit. - */ -int hi6421_spmi_pmic_read(struct hi6421_spmi_pmic *pmic, int reg) -{ - struct spmi_device *pdev; - u8 read_value = 0; - u32 ret; - - pdev = to_spmi_device(pmic->dev); - if (!pdev) { - pr_err("%s: pdev get failed!\n", __func__); - return -ENODEV; - } - - ret = spmi_ext_register_readl(pdev, reg, &read_value, 1); - if (ret) { - pr_err("%s: spmi_ext_register_readl failed!\n", __func__); - return ret; - } - return read_value; -} -EXPORT_SYMBOL(hi6421_spmi_pmic_read); - -int hi6421_spmi_pmic_write(struct hi6421_spmi_pmic *pmic, int reg, u32 val) -{ - struct spmi_device *pdev; - u32 ret; - - pdev = to_spmi_device(pmic->dev); - if (!pdev) { - pr_err("%s: pdev get failed!\n", __func__); - return -ENODEV; - } - - ret = spmi_ext_register_writel(pdev, reg, (unsigned char *)&val, 1); - if (ret) - pr_err("%s: spmi_ext_register_writel failed!\n", __func__); - - return ret; -} -EXPORT_SYMBOL(hi6421_spmi_pmic_write); - -int hi6421_spmi_pmic_rmw(struct hi6421_spmi_pmic *pmic, int reg, - u32 mask, u32 bits) -{ - unsigned long flags; - u32 data; - int ret; - - spin_lock_irqsave(&pmic->lock, flags); - data = hi6421_spmi_pmic_read(pmic, reg) & ~mask; - data |= mask & bits; - ret = hi6421_spmi_pmic_write(pmic, reg, data); - spin_unlock_irqrestore(&pmic->lock, flags); - - return ret; -} -EXPORT_SYMBOL(hi6421_spmi_pmic_rmw); - -static irqreturn_t hi6421_spmi_irq_handler(int irq, void *data) -{ - struct hi6421_spmi_pmic *pmic = (struct hi6421_spmi_pmic *)data; - unsigned long pending; - int i, offset; - - for (i = 0; i < HISI_IRQ_ARRAY; i++) { - pending = hi6421_spmi_pmic_read(pmic, (i + SOC_PMIC_IRQ0_ADDR)); - pending &= HISI_MASK_FIELD; - if (pending != 0) - pr_debug("pending[%d]=0x%lx\n\r", i, pending); - - hi6421_spmi_pmic_write(pmic, (i + SOC_PMIC_IRQ0_ADDR), pending); - - /* solve powerkey order */ - if ((i == HISI_IRQ_KEY_NUM) && - ((pending & HISI_IRQ_KEY_VALUE) == HISI_IRQ_KEY_VALUE)) { - generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_DOWN]); - generic_handle_irq(pmic->irqs[HISI_IRQ_KEY_UP]); - pending &= (~HISI_IRQ_KEY_VALUE); - } - - if (pending) { - for_each_set_bit(offset, &pending, HISI_BITS) - generic_handle_irq(pmic->irqs[offset + i * HISI_BITS]); - } - } - - return IRQ_HANDLED; -} - -static void hi6421_spmi_irq_mask(struct irq_data *d) -{ - struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d); - u32 data, offset; - unsigned long flags; - - offset = (irqd_to_hwirq(d) >> 3); - offset += SOC_PMIC_IRQ_MASK_0_ADDR; - - spin_lock_irqsave(&pmic->lock, flags); - data = hi6421_spmi_pmic_read(pmic, offset); - data |= (1 << (irqd_to_hwirq(d) & 0x07)); - hi6421_spmi_pmic_write(pmic, offset, data); - spin_unlock_irqrestore(&pmic->lock, flags); -} - -static void hi6421_spmi_irq_unmask(struct irq_data *d) -{ - struct hi6421_spmi_pmic *pmic = irq_data_get_irq_chip_data(d); - u32 data, offset; - unsigned long flags; - - offset = (irqd_to_hwirq(d) >> 3); - offset += SOC_PMIC_IRQ_MASK_0_ADDR; - - spin_lock_irqsave(&pmic->lock, flags); - data = hi6421_spmi_pmic_read(pmic, offset); - data &= ~(1 << (irqd_to_hwirq(d) & 0x07)); - hi6421_spmi_pmic_write(pmic, offset, data); - spin_unlock_irqrestore(&pmic->lock, flags); -} - -static struct irq_chip hi6421_spmi_pmu_irqchip = { - .name = "hisi-irq", - .irq_mask = hi6421_spmi_irq_mask, - .irq_unmask = hi6421_spmi_irq_unmask, - .irq_disable = hi6421_spmi_irq_mask, - .irq_enable = hi6421_spmi_irq_unmask, -}; - -static int hi6421_spmi_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw) -{ - struct hi6421_spmi_pmic *pmic = d->host_data; - - irq_set_chip_and_handler_name(virq, &hi6421_spmi_pmu_irqchip, - handle_simple_irq, "hisi"); - irq_set_chip_data(virq, pmic); - irq_set_irq_type(virq, IRQ_TYPE_NONE); - - return 0; -} - -static const struct irq_domain_ops hi6421_spmi_domain_ops = { - .map = hi6421_spmi_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void hi6421_spmi_pmic_irq_prc(struct hi6421_spmi_pmic *pmic) -{ - int i, pending; - - for (i = 0 ; i < HISI_IRQ_ARRAY; i++) - hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ_MASK_0_ADDR + i, - HISI_MASK_STATE); - - for (i = 0 ; i < HISI_IRQ_ARRAY; i++) { - pending = hi6421_spmi_pmic_read(pmic, SOC_PMIC_IRQ0_ADDR + i); - - pr_debug("PMU IRQ address value:irq[0x%x] = 0x%x\n", - SOC_PMIC_IRQ0_ADDR + i, pending); - hi6421_spmi_pmic_write(pmic, SOC_PMIC_IRQ0_ADDR + i, - HISI_MASK_STATE); - } -} - -static int hi6421_spmi_pmic_probe(struct spmi_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct hi6421_spmi_pmic *pmic; - unsigned int virq; - int ret, i; - - pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); - if (!pmic) - return -ENOMEM; - - spin_lock_init(&pmic->lock); - - pmic->dev = dev; - - pmic->gpio = of_get_gpio(np, 0); - if (pmic->gpio < 0) - return pmic->gpio; - - if (!gpio_is_valid(pmic->gpio)) - return -EINVAL; - - ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic"); - if (ret < 0) { - dev_err(dev, "failed to request gpio%d\n", pmic->gpio); - return ret; - } - - pmic->irq = gpio_to_irq(pmic->gpio); - - hi6421_spmi_pmic_irq_prc(pmic); - - pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL); - if (!pmic->irqs) - goto irq_malloc; - - pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0, - &hi6421_spmi_domain_ops, pmic); - if (!pmic->domain) { - dev_err(dev, "failed irq domain add simple!\n"); - ret = -ENODEV; - goto irq_malloc; - } - - for (i = 0; i < HISI_IRQ_NUM; i++) { - virq = irq_create_mapping(pmic->domain, i); - if (!virq) { - dev_err(dev, "Failed mapping hwirq\n"); - ret = -ENOSPC; - goto irq_malloc; - } - pmic->irqs[i] = virq; - dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n", - __func__, i, pmic->irqs[i]); - } - - ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL, - IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND, - "pmic", pmic); - if (ret < 0) { - dev_err(dev, "could not claim pmic IRQ: error %d\n", ret); - goto irq_malloc; - } - - dev_set_drvdata(&pdev->dev, pmic); - - /* - * The logic below will rely that the pmic is already stored at - * drvdata. - */ - dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n", - pdev->dev.of_node); - ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, - hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs), - NULL, 0, NULL); - if (!ret) - return 0; - - dev_err(dev, "Failed to add child devices: %d\n", ret); - -irq_malloc: - free_irq(pmic->irq, pmic); - - return ret; -} - -static void hi6421_spmi_pmic_remove(struct spmi_device *pdev) -{ - struct hi6421_spmi_pmic *pmic = dev_get_drvdata(&pdev->dev); - - free_irq(pmic->irq, pmic); -} - -static const struct of_device_id pmic_spmi_id_table[] = { - { .compatible = "hisilicon,hi6421-spmi" }, - { } -}; -MODULE_DEVICE_TABLE(of, pmic_spmi_id_table); - -static struct spmi_driver hi6421_spmi_pmic_driver = { - .driver = { - .name = "hi6421-spmi-pmic", - .of_match_table = pmic_spmi_id_table, - }, - .probe = hi6421_spmi_pmic_probe, - .remove = hi6421_spmi_pmic_remove, -}; -module_spmi_driver(hi6421_spmi_pmic_driver); - -MODULE_DESCRIPTION("HiSilicon Hi6421v600 SPMI PMIC driver"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml b/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml deleted file mode 100644 index 80e74c261e05..000000000000 --- a/drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml +++ /dev/null @@ -1,159 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/mfd/hisilicon,hi6421-spmi-pmic.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: HiSilicon 6421v600 SPMI PMIC - -maintainers: - - Mauro Carvalho Chehab - -description: | - HiSilicon 6421v600 should be connected inside a MIPI System Power Management - (SPMI) bus. It provides interrupts and power supply. - - The GPIO and interrupt settings are represented as part of the top-level PMIC - node. - - The SPMI controller part is provided by - drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml. - -properties: - $nodename: - pattern: "pmic@[0-9a-f]" - - compatible: - const: hisilicon,hi6421v600-spmi - - reg: - maxItems: 1 - - '#interrupt-cells': - const: 2 - - interrupt-controller: - description: - Identify that the PMIC is capable of behaving as an interrupt controller. - - gpios: - maxItems: 1 - - regulators: - type: object - - properties: - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - - patternProperties: - '^ldo[0-9]+@[0-9a-f]$': - type: object - - $ref: "/schemas/regulator/regulator.yaml#" - - properties: - reg: - description: Enable register. - - '#address-cells': - const: 1 - - '#size-cells': - const: 0 - - vsel-reg: - description: Voltage selector register. - - enable-mask: - description: Bitmask used to enable the regulator. - - voltage-table: - description: Table with the selector items for the voltage regulator. - minItems: 2 - maxItems: 16 - - off-on-delay-us: - description: Time required for changing state to enabled in microseconds. - - startup-delay-us: - description: Startup time in microseconds. - - idle-mode-mask: - description: Bitmask used to put the regulator on idle mode. - - eco-microamp: - description: Maximum current while on idle mode. - - required: - - reg - - vsel-reg - - enable-mask - - voltage-table - - off-on-delay-us - - startup-delay-us - -required: - - compatible - - reg - - regulators - -examples: - - | - /* pmic properties */ - - pmic: pmic at 0 { - compatible = "hisilicon,hi6421-spmi"; - reg = <0 0>; - - #interrupt-cells = <2>; - interrupt-controller; - gpios = <&gpio28 0 0>; - - regulators { - #address-cells = <1>; - #size-cells = <0>; - - ldo3: ldo3 at 16 { - reg = <0x16>; - vsel-reg = <0x51>; - - regulator-name = "ldo3"; - regulator-min-microvolt = <1500000>; - regulator-max-microvolt = <2000000>; - regulator-boot-on; - - enable-mask = <0x01>; - - voltage-table = <1500000>, <1550000>, <1600000>, <1650000>, - <1700000>, <1725000>, <1750000>, <1775000>, - <1800000>, <1825000>, <1850000>, <1875000>, - <1900000>, <1925000>, <1950000>, <2000000>; - off-on-delay-us = <20000>; - startup-delay-us = <120>; - }; - - ldo4: ldo4 at 17 { /* 40 PIN */ - reg = <0x17>; - vsel-reg = <0x52>; - - regulator-name = "ldo4"; - regulator-min-microvolt = <1725000>; - regulator-max-microvolt = <1900000>; - regulator-boot-on; - - enable-mask = <0x01>; - idle-mode-mask = <0x10>; - eco-microamp = <10000>; - - hi6421-vsel = <0x52 0x07>; - voltage-table = <1725000>, <1750000>, <1775000>, <1800000>, - <1825000>, <1850000>, <1875000>, <1900000>; - off-on-delay-us = <20000>; - startup-delay-us = <120>; - }; - }; - }; -- 2.28.0 From mchehab+huawei at kernel.org Mon Nov 16 12:59:28 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Mon, 16 Nov 2020 13:59:28 +0100 Subject: [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging In-Reply-To: References: Message-ID: <7e01d84b31d561fa4df1d42369e4222f4a41a8d3.1605530560.git.mchehab+huawei@kernel.org> The Hisilicon 6421v600 SPMI driver is ready for mainstream. So, move it from staging. Signed-off-by: Mauro Carvalho Chehab --- .../spmi/hisilicon,hisi-spmi-controller.yaml | 62 +++ MAINTAINERS | 7 + drivers/spmi/Kconfig | 9 + drivers/spmi/Makefile | 1 + drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++++++++++ drivers/staging/hikey9xx/Kconfig | 11 - drivers/staging/hikey9xx/Makefile | 1 - .../staging/hikey9xx/hisi-spmi-controller.c | 358 ------------------ .../hisilicon,hisi-spmi-controller.yaml | 62 --- 9 files changed, 437 insertions(+), 432 deletions(-) create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml create mode 100644 drivers/spmi/hisi-spmi-controller.c delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml diff --git a/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml new file mode 100644 index 000000000000..f2a56fa4e78e --- /dev/null +++ b/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml @@ -0,0 +1,62 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: HiSilicon SPMI controller + +maintainers: + - Mauro Carvalho Chehab + +description: | + The HiSilicon SPMI BUS controller is found on some Kirin-based designs. + It is a MIPI System Power Management (SPMI) controller. + + The PMIC part is provided by + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. + +properties: + $nodename: + pattern: "spmi@[0-9a-f]" + + compatible: + const: hisilicon,kirin970-spmi-controller + + reg: + maxItems: 1 + + spmi-channel: + description: | + number of the Kirin 970 SPMI channel where the SPMI devices are connected. + +required: + - compatible + - reg + - spmi-channel + +patternProperties: + "^pmic@[0-9a-f]$": + description: | + PMIC properties, which are specific to the used SPMI PMIC device(s). + When used in combination with HiSilicon 6421v600, the properties + are documented at + drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. + +examples: + - | + bus { + #address-cells = <2>; + #size-cells = <2>; + + spmi: spmi at fff24000 { + compatible = "hisilicon,kirin970-spmi-controller"; + status = "ok"; + reg = <0x0 0xfff24000 0x0 0x1000>; + spmi-channel = <2>; + + pmic at 0 { + /* pmic properties */ + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 14266bb79ff8..14bc7b45ed50 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7987,6 +7987,13 @@ F: drivers/crypto/hisilicon/sec2/sec_crypto.c F: drivers/crypto/hisilicon/sec2/sec_crypto.h F: drivers/crypto/hisilicon/sec2/sec_main.c +HISILICON SPMI CONTROLLER DRIVER FOR HIKEY 970 +M: Mauro Carvalho Chehab +L: linux-kernel at vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml +F: drivers/spmi/hisi-spmi-controller.c + HISILICON STAGING DRIVERS FOR HIKEY 960/970 M: Mauro Carvalho Chehab L: devel at driverdev.osuosl.org diff --git a/drivers/spmi/Kconfig b/drivers/spmi/Kconfig index a53bad541f1a..2874b6c26028 100644 --- a/drivers/spmi/Kconfig +++ b/drivers/spmi/Kconfig @@ -11,6 +11,15 @@ menuconfig SPMI if SPMI +config SPMI_HISI3670 + tristate "Hisilicon 3670 SPMI Controller" + select IRQ_DOMAIN_HIERARCHY + depends on HAS_IOMEM + help + If you say yes to this option, support will be included for the + built-in SPMI PMIC Arbiter interface on Hisilicon 3670 + processors. + config SPMI_MSM_PMIC_ARB tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)" select IRQ_DOMAIN_HIERARCHY diff --git a/drivers/spmi/Makefile b/drivers/spmi/Makefile index 55a94cadeffe..6e092e6f290c 100644 --- a/drivers/spmi/Makefile +++ b/drivers/spmi/Makefile @@ -4,4 +4,5 @@ # obj-$(CONFIG_SPMI) += spmi.o +obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o obj-$(CONFIG_SPMI_MSM_PMIC_ARB) += spmi-pmic-arb.o diff --git a/drivers/spmi/hisi-spmi-controller.c b/drivers/spmi/hisi-spmi-controller.c new file mode 100644 index 000000000000..f831c43f4783 --- /dev/null +++ b/drivers/spmi/hisi-spmi-controller.c @@ -0,0 +1,358 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * SPMI register addr + */ +#define SPMI_CHANNEL_OFFSET 0x0300 +#define SPMI_SLAVE_OFFSET 0x20 + +#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100 + +#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104 +#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108 +#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c +#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110 + +#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200 + +#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204 +#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208 +#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c +#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210 + +#define SPMI_PER_DATAREG_BYTE 4 +/* + * SPMI cmd register + */ +#define SPMI_APB_SPMI_CMD_EN BIT(31) +#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24 +#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20 +#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16 +#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0 + +/* Command Opcodes */ + +enum spmi_controller_cmd_op_code { + SPMI_CMD_REG_ZERO_WRITE = 0, + SPMI_CMD_REG_WRITE = 1, + SPMI_CMD_REG_READ = 2, + SPMI_CMD_EXT_REG_WRITE = 3, + SPMI_CMD_EXT_REG_READ = 4, + SPMI_CMD_EXT_REG_WRITE_L = 5, + SPMI_CMD_EXT_REG_READ_L = 6, + SPMI_CMD_REG_RESET = 7, + SPMI_CMD_REG_SLEEP = 8, + SPMI_CMD_REG_SHUTDOWN = 9, + SPMI_CMD_REG_WAKEUP = 10, +}; + +/* + * SPMI status register + */ +#define SPMI_APB_TRANS_DONE BIT(0) +#define SPMI_APB_TRANS_FAIL BIT(2) + +/* Command register fields */ +#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16 + +/* Maximum number of support PMIC peripherals */ +#define SPMI_CONTROLLER_TIMEOUT_US 1000 +#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16 + +struct spmi_controller_dev { + struct spmi_controller *controller; + struct device *dev; + void __iomem *base; + spinlock_t lock; + u32 channel; +}; + +static int spmi_controller_wait_for_done(struct device *dev, + struct spmi_controller_dev *ctrl_dev, + void __iomem *base, u8 sid, u16 addr) +{ + u32 timeout = SPMI_CONTROLLER_TIMEOUT_US; + u32 status, offset; + + offset = SPMI_APB_SPMI_STATUS_BASE_ADDR; + offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid; + + do { + status = readl(base + offset); + + if (status & SPMI_APB_TRANS_DONE) { + if (status & SPMI_APB_TRANS_FAIL) { + dev_err(dev, "%s: transaction failed (0x%x)\n", + __func__, status); + return -EIO; + } + dev_dbg(dev, "%s: status 0x%x\n", __func__, status); + return 0; + } + udelay(1); + } while (timeout--); + + dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status); + return -ETIMEDOUT; +} + +static int spmi_read_cmd(struct spmi_controller *ctrl, + u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc) +{ + struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); + u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; + unsigned long flags; + u8 *buf = __buf; + u32 cmd, data; + int rc; + u8 op_code, i; + + if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { + dev_err(&ctrl->dev, + "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", + SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); + return -EINVAL; + } + + switch (opc) { + case SPMI_CMD_READ: + op_code = SPMI_CMD_REG_READ; + break; + case SPMI_CMD_EXT_READ: + op_code = SPMI_CMD_EXT_REG_READ; + break; + case SPMI_CMD_EXT_READL: + op_code = SPMI_CMD_EXT_REG_READ_L; + break; + default: + dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc); + return -EINVAL; + } + + cmd = SPMI_APB_SPMI_CMD_EN | + (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | + ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | + ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */ + ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */ + + spin_lock_irqsave(&spmi_controller->lock, flags); + + writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); + + rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, + spmi_controller->base, slave_id, slave_addr); + if (rc) + goto done; + + for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { + data = readl(spmi_controller->base + chnl_ofst + + SPMI_SLAVE_OFFSET * slave_id + + SPMI_APB_SPMI_RDATA0_BASE_ADDR + + i * SPMI_PER_DATAREG_BYTE); + data = be32_to_cpu((__be32)data); + if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { + memcpy(buf, &data, sizeof(data)); + buf += sizeof(data); + } else { + memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE); + buf += (bc % SPMI_PER_DATAREG_BYTE); + } + } + +done: + spin_unlock_irqrestore(&spmi_controller->lock, flags); + if (rc) + dev_err(&ctrl->dev, + "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", + opc, slave_id, slave_addr, bc + 1); + else + dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n", + __func__, slave_id, slave_addr, (int)bc, __buf); + + return rc; +} + +static int spmi_write_cmd(struct spmi_controller *ctrl, + u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc) +{ + struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); + u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; + const u8 *buf = __buf; + unsigned long flags; + u32 cmd, data; + int rc; + u8 op_code, i; + + if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { + dev_err(&ctrl->dev, + "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", + SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); + return -EINVAL; + } + + switch (opc) { + case SPMI_CMD_WRITE: + op_code = SPMI_CMD_REG_WRITE; + break; + case SPMI_CMD_EXT_WRITE: + op_code = SPMI_CMD_EXT_REG_WRITE; + break; + case SPMI_CMD_EXT_WRITEL: + op_code = SPMI_CMD_EXT_REG_WRITE_L; + break; + default: + dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc); + return -EINVAL; + } + + cmd = SPMI_APB_SPMI_CMD_EN | + (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | + ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | + ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | + ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); + + /* Write data to FIFOs */ + spin_lock_irqsave(&spmi_controller->lock, flags); + + for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { + data = 0; + if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { + memcpy(&data, buf, sizeof(data)); + buf += sizeof(data); + } else { + memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE); + buf += (bc % SPMI_PER_DATAREG_BYTE); + } + + writel((u32)cpu_to_be32(data), + spmi_controller->base + chnl_ofst + + SPMI_APB_SPMI_WDATA0_BASE_ADDR + + SPMI_PER_DATAREG_BYTE * i); + } + + /* Start the transaction */ + writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); + + rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, + spmi_controller->base, slave_id, + slave_addr); + spin_unlock_irqrestore(&spmi_controller->lock, flags); + + if (rc) + dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", + opc, slave_id, slave_addr, bc); + else + dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n", + __func__, slave_id, slave_addr, (int)bc, __buf); + + return rc; +} + +static int spmi_controller_probe(struct platform_device *pdev) +{ + struct spmi_controller_dev *spmi_controller; + struct spmi_controller *ctrl; + struct resource *iores; + int ret; + + ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller)); + if (!ctrl) { + dev_err(&pdev->dev, "can not allocate spmi_controller data\n"); + return -ENOMEM; + } + spmi_controller = spmi_controller_get_drvdata(ctrl); + spmi_controller->controller = ctrl; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iores) { + dev_err(&pdev->dev, "can not get resource!\n"); + return -EINVAL; + } + + spmi_controller->base = devm_ioremap(&pdev->dev, iores->start, + resource_size(iores)); + if (!spmi_controller->base) { + dev_err(&pdev->dev, "can not remap base addr!\n"); + return -EADDRNOTAVAIL; + } + + ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel", + &spmi_controller->channel); + if (ret) { + dev_err(&pdev->dev, "can not get channel\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, spmi_controller); + dev_set_drvdata(&ctrl->dev, spmi_controller); + + spin_lock_init(&spmi_controller->lock); + + ctrl->nr = spmi_controller->channel; + ctrl->dev.parent = pdev->dev.parent; + ctrl->dev.of_node = of_node_get(pdev->dev.of_node); + + /* Callbacks */ + ctrl->read_cmd = spmi_read_cmd; + ctrl->write_cmd = spmi_write_cmd; + + ret = spmi_controller_add(ctrl); + if (ret) + dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret); + + return ret; +} + +static int spmi_del_controller(struct platform_device *pdev) +{ + struct spmi_controller *ctrl = platform_get_drvdata(pdev); + + spmi_controller_remove(ctrl); + kfree(ctrl); + return 0; +} + +static const struct of_device_id spmi_controller_match_table[] = { + { + .compatible = "hisilicon,kirin970-spmi-controller", + }, + {} +}; +MODULE_DEVICE_TABLE(of, spmi_controller_match_table); + +static struct platform_driver spmi_controller_driver = { + .probe = spmi_controller_probe, + .remove = spmi_del_controller, + .driver = { + .name = "hisi_spmi_controller", + .of_match_table = spmi_controller_match_table, + }, +}; + +static int __init spmi_controller_init(void) +{ + return platform_driver_register(&spmi_controller_driver); +} +postcore_initcall(spmi_controller_init); + +static void __exit spmi_controller_exit(void) +{ + platform_driver_unregister(&spmi_controller_driver); +} +module_exit(spmi_controller_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("1.0"); +MODULE_ALIAS("platform:spmi_controller"); diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index 0e97b5b9a56a..69392e42cd0d 100644 --- a/drivers/staging/hikey9xx/Kconfig +++ b/drivers/staging/hikey9xx/Kconfig @@ -1,16 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -# to be placed at drivers/spmi -config SPMI_HISI3670 - tristate "Hisilicon 3670 SPMI Controller" - select IRQ_DOMAIN_HIERARCHY - depends on HAS_IOMEM - depends on SPMI - help - If you say yes to this option, support will be included for the - built-in SPMI PMIC Arbiter interface on Hisilicon 3670 - processors. - # to be placed at drivers/mfd config MFD_HI6421_SPMI tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC" diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile index 9371dcc3d35b..347880fd378f 100644 --- a/drivers/staging/hikey9xx/Makefile +++ b/drivers/staging/hikey9xx/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c deleted file mode 100644 index f831c43f4783..000000000000 --- a/drivers/staging/hikey9xx/hisi-spmi-controller.c +++ /dev/null @@ -1,358 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * SPMI register addr - */ -#define SPMI_CHANNEL_OFFSET 0x0300 -#define SPMI_SLAVE_OFFSET 0x20 - -#define SPMI_APB_SPMI_CMD_BASE_ADDR 0x0100 - -#define SPMI_APB_SPMI_WDATA0_BASE_ADDR 0x0104 -#define SPMI_APB_SPMI_WDATA1_BASE_ADDR 0x0108 -#define SPMI_APB_SPMI_WDATA2_BASE_ADDR 0x010c -#define SPMI_APB_SPMI_WDATA3_BASE_ADDR 0x0110 - -#define SPMI_APB_SPMI_STATUS_BASE_ADDR 0x0200 - -#define SPMI_APB_SPMI_RDATA0_BASE_ADDR 0x0204 -#define SPMI_APB_SPMI_RDATA1_BASE_ADDR 0x0208 -#define SPMI_APB_SPMI_RDATA2_BASE_ADDR 0x020c -#define SPMI_APB_SPMI_RDATA3_BASE_ADDR 0x0210 - -#define SPMI_PER_DATAREG_BYTE 4 -/* - * SPMI cmd register - */ -#define SPMI_APB_SPMI_CMD_EN BIT(31) -#define SPMI_APB_SPMI_CMD_TYPE_OFFSET 24 -#define SPMI_APB_SPMI_CMD_LENGTH_OFFSET 20 -#define SPMI_APB_SPMI_CMD_SLAVEID_OFFSET 16 -#define SPMI_APB_SPMI_CMD_ADDR_OFFSET 0 - -/* Command Opcodes */ - -enum spmi_controller_cmd_op_code { - SPMI_CMD_REG_ZERO_WRITE = 0, - SPMI_CMD_REG_WRITE = 1, - SPMI_CMD_REG_READ = 2, - SPMI_CMD_EXT_REG_WRITE = 3, - SPMI_CMD_EXT_REG_READ = 4, - SPMI_CMD_EXT_REG_WRITE_L = 5, - SPMI_CMD_EXT_REG_READ_L = 6, - SPMI_CMD_REG_RESET = 7, - SPMI_CMD_REG_SLEEP = 8, - SPMI_CMD_REG_SHUTDOWN = 9, - SPMI_CMD_REG_WAKEUP = 10, -}; - -/* - * SPMI status register - */ -#define SPMI_APB_TRANS_DONE BIT(0) -#define SPMI_APB_TRANS_FAIL BIT(2) - -/* Command register fields */ -#define SPMI_CONTROLLER_CMD_MAX_BYTE_COUNT 16 - -/* Maximum number of support PMIC peripherals */ -#define SPMI_CONTROLLER_TIMEOUT_US 1000 -#define SPMI_CONTROLLER_MAX_TRANS_BYTES 16 - -struct spmi_controller_dev { - struct spmi_controller *controller; - struct device *dev; - void __iomem *base; - spinlock_t lock; - u32 channel; -}; - -static int spmi_controller_wait_for_done(struct device *dev, - struct spmi_controller_dev *ctrl_dev, - void __iomem *base, u8 sid, u16 addr) -{ - u32 timeout = SPMI_CONTROLLER_TIMEOUT_US; - u32 status, offset; - - offset = SPMI_APB_SPMI_STATUS_BASE_ADDR; - offset += SPMI_CHANNEL_OFFSET * ctrl_dev->channel + SPMI_SLAVE_OFFSET * sid; - - do { - status = readl(base + offset); - - if (status & SPMI_APB_TRANS_DONE) { - if (status & SPMI_APB_TRANS_FAIL) { - dev_err(dev, "%s: transaction failed (0x%x)\n", - __func__, status); - return -EIO; - } - dev_dbg(dev, "%s: status 0x%x\n", __func__, status); - return 0; - } - udelay(1); - } while (timeout--); - - dev_err(dev, "%s: timeout, status 0x%x\n", __func__, status); - return -ETIMEDOUT; -} - -static int spmi_read_cmd(struct spmi_controller *ctrl, - u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc) -{ - struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); - u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; - unsigned long flags; - u8 *buf = __buf; - u32 cmd, data; - int rc; - u8 op_code, i; - - if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { - dev_err(&ctrl->dev, - "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", - SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); - return -EINVAL; - } - - switch (opc) { - case SPMI_CMD_READ: - op_code = SPMI_CMD_REG_READ; - break; - case SPMI_CMD_EXT_READ: - op_code = SPMI_CMD_EXT_REG_READ; - break; - case SPMI_CMD_EXT_READL: - op_code = SPMI_CMD_EXT_REG_READ_L; - break; - default: - dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc); - return -EINVAL; - } - - cmd = SPMI_APB_SPMI_CMD_EN | - (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | - ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | - ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */ - ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */ - - spin_lock_irqsave(&spmi_controller->lock, flags); - - writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); - - rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, - spmi_controller->base, slave_id, slave_addr); - if (rc) - goto done; - - for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { - data = readl(spmi_controller->base + chnl_ofst + - SPMI_SLAVE_OFFSET * slave_id + - SPMI_APB_SPMI_RDATA0_BASE_ADDR + - i * SPMI_PER_DATAREG_BYTE); - data = be32_to_cpu((__be32)data); - if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { - memcpy(buf, &data, sizeof(data)); - buf += sizeof(data); - } else { - memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE); - buf += (bc % SPMI_PER_DATAREG_BYTE); - } - } - -done: - spin_unlock_irqrestore(&spmi_controller->lock, flags); - if (rc) - dev_err(&ctrl->dev, - "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", - opc, slave_id, slave_addr, bc + 1); - else - dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n", - __func__, slave_id, slave_addr, (int)bc, __buf); - - return rc; -} - -static int spmi_write_cmd(struct spmi_controller *ctrl, - u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc) -{ - struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); - u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; - const u8 *buf = __buf; - unsigned long flags; - u32 cmd, data; - int rc; - u8 op_code, i; - - if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { - dev_err(&ctrl->dev, - "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", - SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); - return -EINVAL; - } - - switch (opc) { - case SPMI_CMD_WRITE: - op_code = SPMI_CMD_REG_WRITE; - break; - case SPMI_CMD_EXT_WRITE: - op_code = SPMI_CMD_EXT_REG_WRITE; - break; - case SPMI_CMD_EXT_WRITEL: - op_code = SPMI_CMD_EXT_REG_WRITE_L; - break; - default: - dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc); - return -EINVAL; - } - - cmd = SPMI_APB_SPMI_CMD_EN | - (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | - ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | - ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | - ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); - - /* Write data to FIFOs */ - spin_lock_irqsave(&spmi_controller->lock, flags); - - for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { - data = 0; - if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { - memcpy(&data, buf, sizeof(data)); - buf += sizeof(data); - } else { - memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE); - buf += (bc % SPMI_PER_DATAREG_BYTE); - } - - writel((u32)cpu_to_be32(data), - spmi_controller->base + chnl_ofst + - SPMI_APB_SPMI_WDATA0_BASE_ADDR + - SPMI_PER_DATAREG_BYTE * i); - } - - /* Start the transaction */ - writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); - - rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, - spmi_controller->base, slave_id, - slave_addr); - spin_unlock_irqrestore(&spmi_controller->lock, flags); - - if (rc) - dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", - opc, slave_id, slave_addr, bc); - else - dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n", - __func__, slave_id, slave_addr, (int)bc, __buf); - - return rc; -} - -static int spmi_controller_probe(struct platform_device *pdev) -{ - struct spmi_controller_dev *spmi_controller; - struct spmi_controller *ctrl; - struct resource *iores; - int ret; - - ctrl = spmi_controller_alloc(&pdev->dev, sizeof(*spmi_controller)); - if (!ctrl) { - dev_err(&pdev->dev, "can not allocate spmi_controller data\n"); - return -ENOMEM; - } - spmi_controller = spmi_controller_get_drvdata(ctrl); - spmi_controller->controller = ctrl; - - iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) { - dev_err(&pdev->dev, "can not get resource!\n"); - return -EINVAL; - } - - spmi_controller->base = devm_ioremap(&pdev->dev, iores->start, - resource_size(iores)); - if (!spmi_controller->base) { - dev_err(&pdev->dev, "can not remap base addr!\n"); - return -EADDRNOTAVAIL; - } - - ret = of_property_read_u32(pdev->dev.of_node, "spmi-channel", - &spmi_controller->channel); - if (ret) { - dev_err(&pdev->dev, "can not get channel\n"); - return -ENODEV; - } - - platform_set_drvdata(pdev, spmi_controller); - dev_set_drvdata(&ctrl->dev, spmi_controller); - - spin_lock_init(&spmi_controller->lock); - - ctrl->nr = spmi_controller->channel; - ctrl->dev.parent = pdev->dev.parent; - ctrl->dev.of_node = of_node_get(pdev->dev.of_node); - - /* Callbacks */ - ctrl->read_cmd = spmi_read_cmd; - ctrl->write_cmd = spmi_write_cmd; - - ret = spmi_controller_add(ctrl); - if (ret) - dev_err(&pdev->dev, "spmi_add_controller failed with error %d!\n", ret); - - return ret; -} - -static int spmi_del_controller(struct platform_device *pdev) -{ - struct spmi_controller *ctrl = platform_get_drvdata(pdev); - - spmi_controller_remove(ctrl); - kfree(ctrl); - return 0; -} - -static const struct of_device_id spmi_controller_match_table[] = { - { - .compatible = "hisilicon,kirin970-spmi-controller", - }, - {} -}; -MODULE_DEVICE_TABLE(of, spmi_controller_match_table); - -static struct platform_driver spmi_controller_driver = { - .probe = spmi_controller_probe, - .remove = spmi_del_controller, - .driver = { - .name = "hisi_spmi_controller", - .of_match_table = spmi_controller_match_table, - }, -}; - -static int __init spmi_controller_init(void) -{ - return platform_driver_register(&spmi_controller_driver); -} -postcore_initcall(spmi_controller_init); - -static void __exit spmi_controller_exit(void) -{ - platform_driver_unregister(&spmi_controller_driver); -} -module_exit(spmi_controller_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_VERSION("1.0"); -MODULE_ALIAS("platform:spmi_controller"); diff --git a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml b/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml deleted file mode 100644 index f2a56fa4e78e..000000000000 --- a/drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml +++ /dev/null @@ -1,62 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/spmi/hisilicon,hisi-spmi-controller.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: HiSilicon SPMI controller - -maintainers: - - Mauro Carvalho Chehab - -description: | - The HiSilicon SPMI BUS controller is found on some Kirin-based designs. - It is a MIPI System Power Management (SPMI) controller. - - The PMIC part is provided by - drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. - -properties: - $nodename: - pattern: "spmi@[0-9a-f]" - - compatible: - const: hisilicon,kirin970-spmi-controller - - reg: - maxItems: 1 - - spmi-channel: - description: | - number of the Kirin 970 SPMI channel where the SPMI devices are connected. - -required: - - compatible - - reg - - spmi-channel - -patternProperties: - "^pmic@[0-9a-f]$": - description: | - PMIC properties, which are specific to the used SPMI PMIC device(s). - When used in combination with HiSilicon 6421v600, the properties - are documented at - drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml. - -examples: - - | - bus { - #address-cells = <2>; - #size-cells = <2>; - - spmi: spmi at fff24000 { - compatible = "hisilicon,kirin970-spmi-controller"; - status = "ok"; - reg = <0x0 0xfff24000 0x0 0x1000>; - spmi-channel = <2>; - - pmic at 0 { - /* pmic properties */ - }; - }; - }; -- 2.28.0 From mchehab+huawei at kernel.org Mon Nov 16 12:59:30 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Mon, 16 Nov 2020 13:59:30 +0100 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: References: Message-ID: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> This driver is ready for mainstream. Move it out of staging. Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 +- drivers/regulator/Kconfig | 9 + drivers/regulator/Makefile | 1 + drivers/regulator/hi6421v600-regulator.c | 478 ++++++++++++++++++ drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/hikey9xx/Kconfig | 11 - drivers/staging/hikey9xx/Makefile | 3 - drivers/staging/hikey9xx/TODO | 5 - .../staging/hikey9xx/hi6421v600-regulator.c | 478 ------------------ 10 files changed, 489 insertions(+), 506 deletions(-) create mode 100644 drivers/regulator/hi6421v600-regulator.c delete mode 100644 drivers/staging/hikey9xx/Kconfig delete mode 100644 drivers/staging/hikey9xx/Makefile delete mode 100644 drivers/staging/hikey9xx/TODO delete mode 100644 drivers/staging/hikey9xx/hi6421v600-regulator.c diff --git a/MAINTAINERS b/MAINTAINERS index 450c7cbc6725..aa68aee9e684 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8000,12 +8000,7 @@ L: linux-kernel at vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml F: drivers/mfd/hi6421-spmi-pmic.c - -HISILICON STAGING DRIVERS FOR HIKEY 960/970 -M: Mauro Carvalho Chehab -L: devel at driverdev.osuosl.org -S: Maintained -F: drivers/staging/hikey9xx/ +F: drivers/regulator/hi6421v600-regulator.c HISILICON TRUE RANDOM NUMBER GENERATOR V2 SUPPORT M: Zaibo Xu diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 020a00d6696b..08d302c87fa0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -394,6 +394,15 @@ config REGULATOR_HI655X This driver provides support for the voltage regulators of the Hisilicon Hi655x PMIC device. +config REGULATOR_HI6421V600 + tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" + depends on MFD_HI6421_SPMI && OF + depends on REGULATOR + help + This driver provides support for the voltage regulators on + HiSilicon Hi6421v600 PMU / Codec IC. + This is used on Kirin 3670 boards, like HiKey 970. + config REGULATOR_ISL9305 tristate "Intersil ISL9305 regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 6ebae516258e..45d1883de54b 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o obj-$(CONFIG_REGULATOR_HI6421) += hi6421-regulator.o obj-$(CONFIG_REGULATOR_HI6421V530) += hi6421v530-regulator.o +obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o obj-$(CONFIG_REGULATOR_HI655X) += hi655x-regulator.o obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o obj-$(CONFIG_REGULATOR_ISL9305) += isl9305.o diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c new file mode 100644 index 000000000000..614b03c9ddfb --- /dev/null +++ b/drivers/regulator/hi6421v600-regulator.c @@ -0,0 +1,478 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device driver for regulators in Hisi IC + * + * Copyright (c) 2013 Linaro Ltd. + * Copyright (c) 2011 Hisilicon. + * + * Guodong Xu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define rdev_dbg(rdev, fmt, arg...) \ + pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg) + +struct hi6421v600_regulator { + struct regulator_desc rdesc; + struct hi6421_spmi_pmic *pmic; + u32 eco_mode_mask, eco_uA; +}; + +static DEFINE_MUTEX(enable_mutex); + +/* + * helper function to ensure when it returns it is at least 'delay_us' + * microseconds after 'since'. + */ + +static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 reg_val; + + reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); + + rdev_dbg(rdev, + "enable_reg=0x%x, val= 0x%x, enable_state=%d\n", + rdev->desc->enable_reg, + reg_val, (reg_val & rdev->desc->enable_mask)); + + return ((reg_val & rdev->desc->enable_mask) != 0); +} + +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + + /* cannot enable more than one regulator at one time */ + mutex_lock(&enable_mutex); + usleep_range(HISI_REGS_ENA_PROTECT_TIME, + HISI_REGS_ENA_PROTECT_TIME + 1000); + + /* set enable register */ + rdev_dbg(rdev, + "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n", + rdev->desc->off_on_delay, rdev->desc->enable_reg, + rdev->desc->enable_mask); + + hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, + rdev->desc->enable_mask, + rdev->desc->enable_mask); + + mutex_unlock(&enable_mutex); + + return 0; +} + +static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + + /* set enable register to 0 */ + rdev_dbg(rdev, "enable_reg=0x%x, enable_mask=0x%x\n", + rdev->desc->enable_reg, rdev->desc->enable_mask); + + hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, + rdev->desc->enable_mask, 0); + + return 0; +} + +static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 reg_val, selector; + + /* get voltage selector */ + reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->vsel_reg); + + selector = (reg_val & rdev->desc->vsel_mask) >> (ffs(rdev->desc->vsel_mask) - 1); + + rdev_dbg(rdev, + "vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n", + rdev->desc->vsel_reg, reg_val, selector, + rdev->desc->ops->list_voltage(rdev, selector) / 1000); + + return selector; +} + +static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 reg_val; + + if (unlikely(selector >= rdev->desc->n_voltages)) + return -EINVAL; + + reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1); + + /* set voltage selector */ + rdev_dbg(rdev, + "vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n", + rdev->desc->vsel_reg, rdev->desc->vsel_mask, reg_val, + rdev->desc->ops->list_voltage(rdev, selector) / 1000); + + hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, reg_val); + + return 0; +} + +static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + unsigned int mode; + u32 reg_val; + + reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); + + if (reg_val & sreg->eco_mode_mask) + mode = REGULATOR_MODE_IDLE; + else + mode = REGULATOR_MODE_NORMAL; + + rdev_dbg(rdev, + "enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n", + rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val, + mode == REGULATOR_MODE_IDLE ? "idle" : "normal"); + + return mode; +} + +static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + struct hi6421_spmi_pmic *pmic = sreg->pmic; + u32 val; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + val = 0; + break; + case REGULATOR_MODE_IDLE: + val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1); + break; + default: + return -EINVAL; + } + + /* set mode */ + rdev_dbg(rdev, "enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n", + rdev->desc->enable_reg, sreg->eco_mode_mask, val); + + hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, + sreg->eco_mode_mask, val); + + return 0; +} + +static unsigned int +hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, + int input_uV, int output_uV, + int load_uA) +{ + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + + if (load_uA || ((unsigned int)load_uA > sreg->eco_uA)) + return REGULATOR_MODE_NORMAL; + + return REGULATOR_MODE_IDLE; +} + +static int hi6421_spmi_dt_parse(struct platform_device *pdev, + struct hi6421v600_regulator *sreg, + struct regulator_desc *rdesc) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + unsigned int *v_table; + int ret; + + ret = of_property_read_u32(np, "reg", &rdesc->enable_reg); + if (ret) { + dev_err(dev, "missing reg property\n"); + return ret; + } + + ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg); + if (ret) { + dev_err(dev, "missing vsel-reg property\n"); + return ret; + } + + ret = of_property_read_u32(np, "enable-mask", &rdesc->enable_mask); + if (ret) { + dev_err(dev, "missing enable-mask property\n"); + return ret; + } + + /* + * Not all regulators work on idle mode + */ + ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask); + if (ret) { + dev_dbg(dev, "LDO doesn't support economy mode.\n"); + sreg->eco_mode_mask = 0; + sreg->eco_uA = 0; + } else { + ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA); + if (ret) { + dev_err(dev, "missing eco-microamp property\n"); + return ret; + } + } + + /* parse .off-on-delay */ + ret = of_property_read_u32(np, "off-on-delay-us", + &rdesc->off_on_delay); + if (ret) { + dev_err(dev, "missing off-on-delay-us property\n"); + return ret; + } + + /* parse .enable_time */ + ret = of_property_read_u32(np, "startup-delay-us", + &rdesc->enable_time); + if (ret) { + dev_err(dev, "missing startup-delay-us property\n"); + return ret; + } + + /* FIXME: are there a better value for this? */ + rdesc->ramp_delay = rdesc->enable_time; + + /* parse volt_table */ + + rdesc->n_voltages = of_property_count_u32_elems(np, "voltage-table"); + + v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages, + GFP_KERNEL); + if (unlikely(!v_table)) + return -ENOMEM; + rdesc->volt_table = v_table; + + ret = of_property_read_u32_array(np, "voltage-table", + v_table, rdesc->n_voltages); + if (ret) { + dev_err(dev, "missing voltage-table property\n"); + return ret; + } + + /* + * Instead of explicitly requiring a mask for the voltage selector, + * as they all start from bit zero (at least on the known LDOs), + * just use the number of voltages at the voltage table, getting the + * minimal mask that would pick everything. + */ + rdesc->vsel_mask = (1 << (fls(rdesc->n_voltages) - 1)) - 1; + + dev_dbg(dev, "voltage selector settings: reg: 0x%x, mask: 0x%x\n", + rdesc->vsel_reg, rdesc->vsel_mask); + + return 0; +} + +static const struct regulator_ops hi6421_spmi_ldo_rops = { + .is_enabled = hi6421_spmi_regulator_is_enabled, + .enable = hi6421_spmi_regulator_enable, + .disable = hi6421_spmi_regulator_disable, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .get_voltage_sel = hi6421_spmi_regulator_get_voltage_sel, + .set_voltage_sel = hi6421_spmi_regulator_set_voltage_sel, + .get_mode = hi6421_spmi_regulator_get_mode, + .set_mode = hi6421_spmi_regulator_set_mode, + .get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode, +}; + +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev, + struct device_node *np, + struct hi6421_spmi_pmic *pmic) +{ + struct regulation_constraints *constraint; + struct regulator_init_data *initdata; + struct regulator_config config = { }; + struct hi6421v600_regulator *sreg; + struct device *dev = &pdev->dev; + struct regulator_desc *rdesc; + struct regulator_dev *rdev; + const char *supplyname; + int ret; + + initdata = of_get_regulator_init_data(dev, np, NULL); + if (!initdata) { + dev_err(dev, "failed to get regulator data\n"); + return -EINVAL; + } + + sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); + if (!sreg) + return -ENOMEM; + + sreg->pmic = pmic; + rdesc = &sreg->rdesc; + + rdesc->name = initdata->constraints.name; + rdesc->ops = &hi6421_spmi_ldo_rops; + rdesc->type = REGULATOR_VOLTAGE; + rdesc->min_uV = initdata->constraints.min_uV; + + supplyname = of_get_property(np, "supply_name", NULL); + if (supplyname) + initdata->supply_regulator = supplyname; + + /* parse device tree data for regulator specific */ + ret = hi6421_spmi_dt_parse(pdev, sreg, rdesc); + if (ret) + return ret; + + /* hisi regulator supports two modes */ + constraint = &initdata->constraints; + + constraint->valid_modes_mask = REGULATOR_MODE_NORMAL; + if (sreg->eco_mode_mask) { + constraint->valid_modes_mask |= REGULATOR_MODE_IDLE; + constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE; + } + + config.dev = &pdev->dev; + config.init_data = initdata; + config.driver_data = sreg; + config.of_node = pdev->dev.of_node; + + /* register regulator */ + rdev = regulator_register(rdesc, &config); + if (IS_ERR(rdev)) { + dev_err(dev, "failed to register %s\n", + rdesc->name); + return PTR_ERR(rdev); + } + + rdev_dbg(rdev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n", + constraint->valid_modes_mask, constraint->valid_ops_mask); + + dev_set_drvdata(dev, rdev); + + return 0; +} + +static int hi6421_spmi_regulator_probe(struct platform_device *pdev) +{ + struct device *pmic_dev = pdev->dev.parent; + struct device_node *np = pmic_dev->of_node; + struct device_node *regulators, *child; + struct platform_device *new_pdev; + struct hi6421_spmi_pmic *pmic; + int ret; + + /* + * This driver is meant to be called by hi6421-spmi-core, + * which should first set drvdata. If this doesn't happen, hit + * a warn on and return. + */ + pmic = dev_get_drvdata(pmic_dev); + if (WARN_ON(!pmic)) + return -ENODEV; + + regulators = of_get_child_by_name(np, "regulators"); + if (!regulators) { + dev_err(&pdev->dev, "regulator node not found\n"); + return -ENODEV; + } + + /* + * Parse all LDO regulator nodes + */ + for_each_child_of_node(regulators, child) { + dev_dbg(&pdev->dev, "adding child %pOF\n", child); + + new_pdev = platform_device_alloc(child->name, -1); + new_pdev->dev.parent = pmic_dev; + new_pdev->dev.of_node = of_node_get(child); + + ret = platform_device_add(new_pdev); + if (ret < 0) { + platform_device_put(new_pdev); + continue; + } + + ret = hi6421_spmi_regulator_probe_ldo(new_pdev, child, pmic); + if (ret < 0) + platform_device_put(new_pdev); + } + + of_node_put(regulators); + + return 0; +} + +static int hi6421_spmi_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev); + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); + + regulator_unregister(rdev); + + if (rdev->desc->volt_table) + devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table); + + kfree(sreg); + + return 0; +} + +static const struct platform_device_id hi6421v600_regulator_table[] = { + { .name = "hi6421v600-regulator" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, hi6421v600_regulator_table); + +static struct platform_driver hi6421v600_regulator_driver = { + .id_table = hi6421v600_regulator_table, + .driver = { + .name = "hi6421v600-regulator", + }, + .probe = hi6421_spmi_regulator_probe, + .remove = hi6421_spmi_regulator_remove, +}; +module_platform_driver(hi6421v600_regulator_driver); + +MODULE_DESCRIPTION("Hi6421v600 regulator driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2d0310448eba..e6c831c6cccc 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -116,6 +116,4 @@ source "drivers/staging/qlge/Kconfig" source "drivers/staging/wfx/Kconfig" -source "drivers/staging/hikey9xx/Kconfig" - endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 757a892ab5b9..a3b1fd0622f9 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -48,4 +48,3 @@ obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/ obj-$(CONFIG_KPC2000) += kpc2000/ obj-$(CONFIG_QLGE) += qlge/ obj-$(CONFIG_WFX) += wfx/ -obj-y += hikey9xx/ diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig deleted file mode 100644 index 1afb8648a2c4..000000000000 --- a/drivers/staging/hikey9xx/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# to be placed at drivers/regulator -config REGULATOR_HI6421V600 - tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" - depends on MFD_HI6421_SPMI && OF - depends on REGULATOR - help - This driver provides support for the voltage regulators on - HiSilicon Hi6421v600 PMU / Codec IC. - This is used on Kirin 3670 boards, like HiKey 970. diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile deleted file mode 100644 index 4d63184e6086..000000000000 --- a/drivers/staging/hikey9xx/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o diff --git a/drivers/staging/hikey9xx/TODO b/drivers/staging/hikey9xx/TODO deleted file mode 100644 index 65e7996a3066..000000000000 --- a/drivers/staging/hikey9xx/TODO +++ /dev/null @@ -1,5 +0,0 @@ -ToDo list: - -- Port other drivers needed by Hikey 960/970; -- Test drivers on Hikey 960; -- Validate device tree bindings. diff --git a/drivers/staging/hikey9xx/hi6421v600-regulator.c b/drivers/staging/hikey9xx/hi6421v600-regulator.c deleted file mode 100644 index 614b03c9ddfb..000000000000 --- a/drivers/staging/hikey9xx/hi6421v600-regulator.c +++ /dev/null @@ -1,478 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Device driver for regulators in Hisi IC - * - * Copyright (c) 2013 Linaro Ltd. - * Copyright (c) 2011 Hisilicon. - * - * Guodong Xu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define rdev_dbg(rdev, fmt, arg...) \ - pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg) - -struct hi6421v600_regulator { - struct regulator_desc rdesc; - struct hi6421_spmi_pmic *pmic; - u32 eco_mode_mask, eco_uA; -}; - -static DEFINE_MUTEX(enable_mutex); - -/* - * helper function to ensure when it returns it is at least 'delay_us' - * microseconds after 'since'. - */ - -static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 reg_val; - - reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); - - rdev_dbg(rdev, - "enable_reg=0x%x, val= 0x%x, enable_state=%d\n", - rdev->desc->enable_reg, - reg_val, (reg_val & rdev->desc->enable_mask)); - - return ((reg_val & rdev->desc->enable_mask) != 0); -} - -static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - - /* cannot enable more than one regulator at one time */ - mutex_lock(&enable_mutex); - usleep_range(HISI_REGS_ENA_PROTECT_TIME, - HISI_REGS_ENA_PROTECT_TIME + 1000); - - /* set enable register */ - rdev_dbg(rdev, - "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n", - rdev->desc->off_on_delay, rdev->desc->enable_reg, - rdev->desc->enable_mask); - - hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, - rdev->desc->enable_mask, - rdev->desc->enable_mask); - - mutex_unlock(&enable_mutex); - - return 0; -} - -static int hi6421_spmi_regulator_disable(struct regulator_dev *rdev) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - - /* set enable register to 0 */ - rdev_dbg(rdev, "enable_reg=0x%x, enable_mask=0x%x\n", - rdev->desc->enable_reg, rdev->desc->enable_mask); - - hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, - rdev->desc->enable_mask, 0); - - return 0; -} - -static int hi6421_spmi_regulator_get_voltage_sel(struct regulator_dev *rdev) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 reg_val, selector; - - /* get voltage selector */ - reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->vsel_reg); - - selector = (reg_val & rdev->desc->vsel_mask) >> (ffs(rdev->desc->vsel_mask) - 1); - - rdev_dbg(rdev, - "vsel_reg=0x%x, value=0x%x, entry=0x%x, voltage=%d mV\n", - rdev->desc->vsel_reg, reg_val, selector, - rdev->desc->ops->list_voltage(rdev, selector) / 1000); - - return selector; -} - -static int hi6421_spmi_regulator_set_voltage_sel(struct regulator_dev *rdev, - unsigned int selector) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 reg_val; - - if (unlikely(selector >= rdev->desc->n_voltages)) - return -EINVAL; - - reg_val = selector << (ffs(rdev->desc->vsel_mask) - 1); - - /* set voltage selector */ - rdev_dbg(rdev, - "vsel_reg=0x%x, mask=0x%x, value=0x%x, voltage=%d mV\n", - rdev->desc->vsel_reg, rdev->desc->vsel_mask, reg_val, - rdev->desc->ops->list_voltage(rdev, selector) / 1000); - - hi6421_spmi_pmic_rmw(pmic, rdev->desc->vsel_reg, - rdev->desc->vsel_mask, reg_val); - - return 0; -} - -static unsigned int hi6421_spmi_regulator_get_mode(struct regulator_dev *rdev) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - unsigned int mode; - u32 reg_val; - - reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); - - if (reg_val & sreg->eco_mode_mask) - mode = REGULATOR_MODE_IDLE; - else - mode = REGULATOR_MODE_NORMAL; - - rdev_dbg(rdev, - "enable_reg=0x%x, eco_mode_mask=0x%x, reg_val=0x%x, %s mode\n", - rdev->desc->enable_reg, sreg->eco_mode_mask, reg_val, - mode == REGULATOR_MODE_IDLE ? "idle" : "normal"); - - return mode; -} - -static int hi6421_spmi_regulator_set_mode(struct regulator_dev *rdev, - unsigned int mode) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - struct hi6421_spmi_pmic *pmic = sreg->pmic; - u32 val; - - switch (mode) { - case REGULATOR_MODE_NORMAL: - val = 0; - break; - case REGULATOR_MODE_IDLE: - val = sreg->eco_mode_mask << (ffs(sreg->eco_mode_mask) - 1); - break; - default: - return -EINVAL; - } - - /* set mode */ - rdev_dbg(rdev, "enable_reg=0x%x, eco_mode_mask=0x%x, value=0x%x\n", - rdev->desc->enable_reg, sreg->eco_mode_mask, val); - - hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, - sreg->eco_mode_mask, val); - - return 0; -} - -static unsigned int -hi6421_spmi_regulator_get_optimum_mode(struct regulator_dev *rdev, - int input_uV, int output_uV, - int load_uA) -{ - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - - if (load_uA || ((unsigned int)load_uA > sreg->eco_uA)) - return REGULATOR_MODE_NORMAL; - - return REGULATOR_MODE_IDLE; -} - -static int hi6421_spmi_dt_parse(struct platform_device *pdev, - struct hi6421v600_regulator *sreg, - struct regulator_desc *rdesc) -{ - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - unsigned int *v_table; - int ret; - - ret = of_property_read_u32(np, "reg", &rdesc->enable_reg); - if (ret) { - dev_err(dev, "missing reg property\n"); - return ret; - } - - ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg); - if (ret) { - dev_err(dev, "missing vsel-reg property\n"); - return ret; - } - - ret = of_property_read_u32(np, "enable-mask", &rdesc->enable_mask); - if (ret) { - dev_err(dev, "missing enable-mask property\n"); - return ret; - } - - /* - * Not all regulators work on idle mode - */ - ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask); - if (ret) { - dev_dbg(dev, "LDO doesn't support economy mode.\n"); - sreg->eco_mode_mask = 0; - sreg->eco_uA = 0; - } else { - ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA); - if (ret) { - dev_err(dev, "missing eco-microamp property\n"); - return ret; - } - } - - /* parse .off-on-delay */ - ret = of_property_read_u32(np, "off-on-delay-us", - &rdesc->off_on_delay); - if (ret) { - dev_err(dev, "missing off-on-delay-us property\n"); - return ret; - } - - /* parse .enable_time */ - ret = of_property_read_u32(np, "startup-delay-us", - &rdesc->enable_time); - if (ret) { - dev_err(dev, "missing startup-delay-us property\n"); - return ret; - } - - /* FIXME: are there a better value for this? */ - rdesc->ramp_delay = rdesc->enable_time; - - /* parse volt_table */ - - rdesc->n_voltages = of_property_count_u32_elems(np, "voltage-table"); - - v_table = devm_kzalloc(dev, sizeof(unsigned int) * rdesc->n_voltages, - GFP_KERNEL); - if (unlikely(!v_table)) - return -ENOMEM; - rdesc->volt_table = v_table; - - ret = of_property_read_u32_array(np, "voltage-table", - v_table, rdesc->n_voltages); - if (ret) { - dev_err(dev, "missing voltage-table property\n"); - return ret; - } - - /* - * Instead of explicitly requiring a mask for the voltage selector, - * as they all start from bit zero (at least on the known LDOs), - * just use the number of voltages at the voltage table, getting the - * minimal mask that would pick everything. - */ - rdesc->vsel_mask = (1 << (fls(rdesc->n_voltages) - 1)) - 1; - - dev_dbg(dev, "voltage selector settings: reg: 0x%x, mask: 0x%x\n", - rdesc->vsel_reg, rdesc->vsel_mask); - - return 0; -} - -static const struct regulator_ops hi6421_spmi_ldo_rops = { - .is_enabled = hi6421_spmi_regulator_is_enabled, - .enable = hi6421_spmi_regulator_enable, - .disable = hi6421_spmi_regulator_disable, - .list_voltage = regulator_list_voltage_table, - .map_voltage = regulator_map_voltage_iterate, - .get_voltage_sel = hi6421_spmi_regulator_get_voltage_sel, - .set_voltage_sel = hi6421_spmi_regulator_set_voltage_sel, - .get_mode = hi6421_spmi_regulator_get_mode, - .set_mode = hi6421_spmi_regulator_set_mode, - .get_optimum_mode = hi6421_spmi_regulator_get_optimum_mode, -}; - -static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev, - struct device_node *np, - struct hi6421_spmi_pmic *pmic) -{ - struct regulation_constraints *constraint; - struct regulator_init_data *initdata; - struct regulator_config config = { }; - struct hi6421v600_regulator *sreg; - struct device *dev = &pdev->dev; - struct regulator_desc *rdesc; - struct regulator_dev *rdev; - const char *supplyname; - int ret; - - initdata = of_get_regulator_init_data(dev, np, NULL); - if (!initdata) { - dev_err(dev, "failed to get regulator data\n"); - return -EINVAL; - } - - sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL); - if (!sreg) - return -ENOMEM; - - sreg->pmic = pmic; - rdesc = &sreg->rdesc; - - rdesc->name = initdata->constraints.name; - rdesc->ops = &hi6421_spmi_ldo_rops; - rdesc->type = REGULATOR_VOLTAGE; - rdesc->min_uV = initdata->constraints.min_uV; - - supplyname = of_get_property(np, "supply_name", NULL); - if (supplyname) - initdata->supply_regulator = supplyname; - - /* parse device tree data for regulator specific */ - ret = hi6421_spmi_dt_parse(pdev, sreg, rdesc); - if (ret) - return ret; - - /* hisi regulator supports two modes */ - constraint = &initdata->constraints; - - constraint->valid_modes_mask = REGULATOR_MODE_NORMAL; - if (sreg->eco_mode_mask) { - constraint->valid_modes_mask |= REGULATOR_MODE_IDLE; - constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE; - } - - config.dev = &pdev->dev; - config.init_data = initdata; - config.driver_data = sreg; - config.of_node = pdev->dev.of_node; - - /* register regulator */ - rdev = regulator_register(rdesc, &config); - if (IS_ERR(rdev)) { - dev_err(dev, "failed to register %s\n", - rdesc->name); - return PTR_ERR(rdev); - } - - rdev_dbg(rdev, "valid_modes_mask: 0x%x, valid_ops_mask: 0x%x\n", - constraint->valid_modes_mask, constraint->valid_ops_mask); - - dev_set_drvdata(dev, rdev); - - return 0; -} - -static int hi6421_spmi_regulator_probe(struct platform_device *pdev) -{ - struct device *pmic_dev = pdev->dev.parent; - struct device_node *np = pmic_dev->of_node; - struct device_node *regulators, *child; - struct platform_device *new_pdev; - struct hi6421_spmi_pmic *pmic; - int ret; - - /* - * This driver is meant to be called by hi6421-spmi-core, - * which should first set drvdata. If this doesn't happen, hit - * a warn on and return. - */ - pmic = dev_get_drvdata(pmic_dev); - if (WARN_ON(!pmic)) - return -ENODEV; - - regulators = of_get_child_by_name(np, "regulators"); - if (!regulators) { - dev_err(&pdev->dev, "regulator node not found\n"); - return -ENODEV; - } - - /* - * Parse all LDO regulator nodes - */ - for_each_child_of_node(regulators, child) { - dev_dbg(&pdev->dev, "adding child %pOF\n", child); - - new_pdev = platform_device_alloc(child->name, -1); - new_pdev->dev.parent = pmic_dev; - new_pdev->dev.of_node = of_node_get(child); - - ret = platform_device_add(new_pdev); - if (ret < 0) { - platform_device_put(new_pdev); - continue; - } - - ret = hi6421_spmi_regulator_probe_ldo(new_pdev, child, pmic); - if (ret < 0) - platform_device_put(new_pdev); - } - - of_node_put(regulators); - - return 0; -} - -static int hi6421_spmi_regulator_remove(struct platform_device *pdev) -{ - struct regulator_dev *rdev = dev_get_drvdata(&pdev->dev); - struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); - - regulator_unregister(rdev); - - if (rdev->desc->volt_table) - devm_kfree(&pdev->dev, (unsigned int *)rdev->desc->volt_table); - - kfree(sreg); - - return 0; -} - -static const struct platform_device_id hi6421v600_regulator_table[] = { - { .name = "hi6421v600-regulator" }, - {}, -}; -MODULE_DEVICE_TABLE(platform, hi6421v600_regulator_table); - -static struct platform_driver hi6421v600_regulator_driver = { - .id_table = hi6421v600_regulator_table, - .driver = { - .name = "hi6421v600-regulator", - }, - .probe = hi6421_spmi_regulator_probe, - .remove = hi6421_spmi_regulator_remove, -}; -module_platform_driver(hi6421v600_regulator_driver); - -MODULE_DESCRIPTION("Hi6421v600 regulator driver"); -MODULE_LICENSE("GPL v2"); - -- 2.28.0 From mchehab+huawei at kernel.org Mon Nov 16 12:59:27 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Mon, 16 Nov 2020 13:59:27 +0100 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: References: Message-ID: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> The phy USB3 driver for Hisilicon 970 (hi3670) is ready for mainstream. Mode it from staging into the main driver's phy/ directory. Signed-off-by: Mauro Carvalho Chehab --- .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ MAINTAINERS | 9 +- drivers/phy/hisilicon/Kconfig | 10 + drivers/phy/hisilicon/Makefile | 1 + drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ drivers/staging/hikey9xx/Kconfig | 11 - drivers/staging/hikey9xx/Makefile | 2 - drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- 9 files changed, 762 insertions(+), 757 deletions(-) create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml diff --git a/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml new file mode 100644 index 000000000000..125a5d6546ae --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Hisilicon Kirin970 USB PHY + +maintainers: + - Mauro Carvalho Chehab +description: |+ + Bindings for USB3 PHY on HiSilicon Kirin 970. + +properties: + compatible: + const: hisilicon,hi3670-usb-phy + + "#phy-cells": + const: 0 + + hisilicon,pericrg-syscon: + $ref: '/schemas/types.yaml#/definitions/phandle' + description: phandle of syscon used to control iso refclk. + + hisilicon,pctrl-syscon: + $ref: '/schemas/types.yaml#/definitions/phandle' + description: phandle of syscon used to control usb tcxo. + + hisilicon,sctrl-syscon: + $ref: '/schemas/types.yaml#/definitions/phandle' + description: phandle of syscon used to control phy deep sleep. + + hisilicon,eye-diagram-param: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Eye diagram for phy. + + hisilicon,tx-vboost-lvl: + $ref: /schemas/types.yaml#/definitions/uint32 + description: TX level vboost for phy. + +required: + - compatible + - hisilicon,pericrg-syscon + - hisilicon,pctrl-syscon + - hisilicon,sctrl-syscon + - hisilicon,eye-diagram-param + - hisilicon,tx-vboost-lvl + - "#phy-cells" + +additionalProperties: false + +examples: + - | + bus { + #address-cells = <2>; + #size-cells = <2>; + + usb3_otg_bc: usb3_otg_bc at ff200000 { + compatible = "syscon", "simple-mfd"; + reg = <0x0 0xff200000 0x0 0x1000>; + + usb_phy { + compatible = "hisilicon,hi3670-usb-phy"; + #phy-cells = <0>; + hisilicon,pericrg-syscon = <&crg_ctrl>; + hisilicon,pctrl-syscon = <&pctrl>; + hisilicon,sctrl-syscon = <&sctrl>; + hisilicon,eye-diagram-param = <0xfdfee4>; + hisilicon,tx-vboost-lvl = <0x5>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index e451dcce054f..14266bb79ff8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -18083,7 +18083,7 @@ L: linux-usb at vger.kernel.org S: Maintained F: drivers/usb/roles/intel-xhci-usb-role-switch.c -USB IP DRIVER FOR HISILICON KIRIN +USB IP DRIVER FOR HISILICON KIRIN 960 M: Yu Chen M: Binghui Wang L: linux-usb at vger.kernel.org @@ -18091,6 +18091,13 @@ S: Maintained F: Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml F: drivers/phy/hisilicon/phy-hi3660-usb3.c +USB IP DRIVER FOR HISILICON KIRIN 970 +M: Mauro Carvalho Chehab +L: linux-usb at vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/phy/hisilicon,kirin970-usb3.yaml +F: drivers/phy/hisilicon/phy-kirin970-usb3.c + USB ISP116X DRIVER M: Olav Kongas L: linux-usb at vger.kernel.org diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig index 1c73053bcc98..4d008cfc279c 100644 --- a/drivers/phy/hisilicon/Kconfig +++ b/drivers/phy/hisilicon/Kconfig @@ -23,6 +23,16 @@ config PHY_HI3660_USB To compile this driver as a module, choose M here. +config PHY_HI3670_USB + tristate "hi3670 USB PHY support" + depends on (ARCH_HISI && ARM64) || COMPILE_TEST + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the HISILICON HI3670 USB PHY. + + To compile this driver as a module, choose M here. + config PHY_HISTB_COMBPHY tristate "HiSilicon STB SoCs COMBPHY support" depends on (ARCH_HISI && ARM64) || COMPILE_TEST diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile index 92e874ae9c74..51729868145b 100644 --- a/drivers/phy/hisilicon/Makefile +++ b/drivers/phy/hisilicon/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o obj-$(CONFIG_PHY_HI3660_USB) += phy-hi3660-usb3.o +obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o diff --git a/drivers/phy/hisilicon/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c new file mode 100644 index 000000000000..4fc013911a78 --- /dev/null +++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c @@ -0,0 +1,671 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform + * + * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd. + * http://www.huawei.com + * + * Authors: Yu Chen + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SCTRL_SCDEEPSLEEPED (0x0) +#define USB_CLK_SELECTED BIT(20) + +#define PERI_CRG_PEREN0 (0x00) +#define PERI_CRG_PERDIS0 (0x04) +#define PERI_CRG_PEREN4 (0x40) +#define PERI_CRG_PERDIS4 (0x44) +#define PERI_CRG_PERRSTEN4 (0x90) +#define PERI_CRG_PERRSTDIS4 (0x94) +#define PERI_CRG_ISODIS (0x148) +#define PERI_CRG_PEREN6 (0x410) +#define PERI_CRG_PERDIS6 (0x414) + +#define USB_REFCLK_ISO_EN BIT(25) + +#define GT_CLK_USB2PHY_REF BIT(19) + +#define PCTRL_PERI_CTRL3 (0x10) +#define PCTRL_PERI_CTRL3_MSK_START (16) +#define USB_TCXO_EN BIT(1) + +#define PCTRL_PERI_CTRL24 (0x64) +#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25) + +#define USB3OTG_CTRL0 (0x00) +#define USB3OTG_CTRL3 (0x0C) +#define USB3OTG_CTRL4 (0x10) +#define USB3OTG_CTRL5 (0x14) +#define USB3OTG_CTRL7 (0x1C) +#define USB_MISC_CFG50 (0x50) +#define USB_MISC_CFG54 (0x54) +#define USB_MISC_CFG58 (0x58) +#define USB_MISC_CFG5C (0x5C) +#define USB_MISC_CFGA0 (0xA0) +#define TCA_CLK_RST (0x200) +#define TCA_INTR_EN (0x204) +#define TCA_INTR_STS (0x208) +#define TCA_GCFG (0x210) +#define TCA_TCPC (0x214) +#define TCA_SYSMODE_CFG (0x218) +#define TCA_VBUS_CTRL (0x240) + +#define CTRL0_USB3_VBUSVLD BIT(7) +#define CTRL0_USB3_VBUSVLD_SEL BIT(6) + +#define CTRL3_USB2_VBUSVLDEXT0 BIT(6) +#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5) + +#define CTRL5_USB2_SIDDQ BIT(0) + +#define CTRL7_USB2_REFCLKSEL_MASK (3 << 3) +#define CTRL7_USB2_REFCLKSEL_ABB (3 << 3) +#define CTRL7_USB2_REFCLKSEL_PAD (2 << 3) + +#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23) + +#define CFG54_USB31PHY_CR_ADDR_MASK (0xFFFF) +#define CFG54_USB31PHY_CR_ADDR_SHIFT (16) +#define CFG54_USB3PHY_REF_USE_PAD BIT(12) +#define CFG54_PHY0_PMA_PWR_STABLE BIT(11) +#define CFG54_PHY0_PCS_PWR_STABLE BIT(9) +#define CFG54_USB31PHY_CR_ACK BIT(7) +#define CFG54_USB31PHY_CR_WR_EN BIT(5) +#define CFG54_USB31PHY_CR_SEL BIT(4) +#define CFG54_USB31PHY_CR_RD_EN BIT(3) +#define CFG54_USB31PHY_CR_CLK BIT(2) +#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1) + +#define CFG58_USB31PHY_CR_DATA_MASK (0xFFFF) +#define CFG58_USB31PHY_CR_DATA_RD_START (16) + +#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1) + +#define CFGA0_VAUX_RESET BIT(9) +#define CFGA0_USB31C_RESET BIT(8) +#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4) +#define CFGA0_USB3PHY_RESET BIT(1) +#define CFGA0_USB2PHY_POR BIT(0) + +#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1) +#define INTR_EN_XA_ACK_EVT_EN BIT(0) + +#define CLK_RST_TCA_REF_CLK_EN BIT(1) +#define CLK_RST_SUSPEND_CLK_EN BIT(0) + +#define GCFG_ROLE_HSTDEV BIT(4) +#define GCFG_OP_MODE (3 << 0) +#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0) + +#define TCPC_VALID BIT(4) +#define TCPC_LOW_POWER_EN BIT(3) +#define TCPC_MUX_CONTROL_MASK (3 << 0) +#define TCPC_MUX_CONTROL_USB31 BIT(0) + +#define SYSMODE_CFG_TYPEC_DISABLE BIT(3) + +#define VBUS_CTRL_POWERPRESENT_OVERRD (3 << 2) +#define VBUS_CTRL_VBUSVALID_OVERRD (3 << 0) + +#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xFDFEE4) +#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5) + +#define TX_VBOOST_LVL_REG (0xf) +#define TX_VBOOST_LVL_START (6) +#define TX_VBOOST_LVL_ENABLE BIT(9) + +struct hi3670_priv { + struct device *dev; + struct regmap *peri_crg; + struct regmap *pctrl; + struct regmap *sctrl; + struct regmap *usb31misc; + + u32 eye_diagram_param; + u32 tx_vboost_lvl; + + u32 peri_crg_offset; + u32 pctrl_offset; + u32 usb31misc_offset; +}; + +static int hi3670_phy_cr_clk(struct regmap *usb31misc) +{ + int ret; + + /* Clock up */ + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK); + if (ret) + return ret; + + /* Clock down */ + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_CLK, 0); + + return ret; +} + +static int hi3670_phy_cr_set_sel(struct regmap *usb31misc) +{ + return regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL); +} + +static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction) +{ + int ret; + + if (direction) + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_WR_EN, + CFG54_USB31PHY_CR_WR_EN); + else + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_RD_EN, + CFG54_USB31PHY_CR_RD_EN); + + if (ret) + return ret; + + ret = hi3670_phy_cr_clk(usb31misc); + if (ret) + return ret; + + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, + CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0); + + return ret; +} + +static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc) +{ + u32 reg; + int retry = 100000; + int ret; + + while (retry-- > 0) { + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); + if (ret) + return ret; + if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK) + return 0; + + ret = hi3670_phy_cr_clk(usb31misc); + if (ret) + return ret; + } + + return -ETIMEDOUT; +} + +static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr) +{ + u32 reg; + int ret; + + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); + if (ret) + return ret; + + reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT); + reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT); + ret = regmap_write(usb31misc, USB_MISC_CFG54, reg); + + return ret; +} + +static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val) +{ + int reg; + int i; + int ret; + + for (i = 0; i < 100; i++) { + ret = hi3670_phy_cr_clk(usb31misc); + if (ret) + return ret; + } + + ret = hi3670_phy_cr_set_sel(usb31misc); + if (ret) + return ret; + + ret = hi3670_phy_cr_set_addr(usb31misc, addr); + if (ret) + return ret; + + ret = hi3670_phy_cr_start(usb31misc, 0); + if (ret) + return ret; + + ret = hi3670_phy_cr_wait_ack(usb31misc); + if (ret) + return ret; + + ret = regmap_read(usb31misc, USB_MISC_CFG58, ®); + if (ret) + return ret; + + *val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) & + CFG58_USB31PHY_CR_DATA_MASK; + + return 0; +} + +static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val) +{ + int i; + int ret; + + for (i = 0; i < 100; i++) { + ret = hi3670_phy_cr_clk(usb31misc); + if (ret) + return ret; + } + + ret = hi3670_phy_cr_set_sel(usb31misc); + if (ret) + return ret; + + ret = hi3670_phy_cr_set_addr(usb31misc, addr); + if (ret) + return ret; + + ret = regmap_write(usb31misc, USB_MISC_CFG58, + val & CFG58_USB31PHY_CR_DATA_MASK); + if (ret) + return ret; + + ret = hi3670_phy_cr_start(usb31misc, 1); + if (ret) + return ret; + + ret = hi3670_phy_cr_wait_ack(usb31misc); + + return ret; +} + +static int hi3670_phy_set_params(struct hi3670_priv *priv) +{ + u32 reg; + int ret; + int retry = 3; + + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4, + priv->eye_diagram_param); + if (ret) { + dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n"); + return ret; + } + + while (retry-- > 0) { + ret = hi3670_phy_cr_read(priv->usb31misc, + TX_VBOOST_LVL_REG, ®); + if (!ret) + break; + + if (ret != -ETIMEDOUT) { + dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n"); + return ret; + } + } + if (ret) + return ret; + + reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START)); + ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg); + if (ret) + dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n"); + + return ret; +} + +static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv) +{ + u32 reg; + + if (!priv->sctrl) { + dev_err(priv->dev, "priv->sctrl is null!\n"); + return 1; + } + + if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) { + dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n"); + return 1; + } + + if ((reg & USB_CLK_SELECTED) == 0) + return 1; + + return 0; +} + +static int hi3670_config_phy_clock(struct hi3670_priv *priv) +{ + u32 val, mask; + int ret; + + if (hi3670_is_abbclk_seleted(priv)) { + /* usb refclk iso disable */ + ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, + USB_REFCLK_ISO_EN); + if (ret) + goto out; + + /* enable usb_tcxo_en */ + ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, + USB_TCXO_EN | + (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START)); + + /* select usbphy clk from abb */ + mask = SC_CLK_USB3PHY_3MUX1_SEL; + ret = regmap_update_bits(priv->pctrl, + PCTRL_PERI_CTRL24, mask, 0); + if (ret) + goto out; + + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, + CFGA0_USB2PHY_REFCLK_SELECT, 0); + if (ret) + goto out; + + ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); + if (ret) + goto out; + val &= ~CTRL7_USB2_REFCLKSEL_MASK; + val |= CTRL7_USB2_REFCLKSEL_ABB; + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); + if (ret) + goto out; + + return 0; + } + + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, + CFG54_USB3PHY_REF_USE_PAD, + CFG54_USB3PHY_REF_USE_PAD); + if (ret) + goto out; + + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, + CFGA0_USB2PHY_REFCLK_SELECT, + CFGA0_USB2PHY_REFCLK_SELECT); + if (ret) + goto out; + + ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); + if (ret) + goto out; + val &= ~CTRL7_USB2_REFCLKSEL_MASK; + val |= CTRL7_USB2_REFCLKSEL_PAD; + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); + if (ret) + goto out; + + ret = regmap_write(priv->peri_crg, + PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF); + if (ret) + goto out; + + return 0; +out: + dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); + return ret; +} + +static int hi3670_config_tca(struct hi3670_priv *priv) +{ + u32 val, mask; + int ret; + + ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff); + if (ret) + goto out; + + ret = regmap_write(priv->usb31misc, TCA_INTR_EN, + INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN); + if (ret) + goto out; + + mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN; + ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0); + if (ret) + goto out; + + ret = regmap_update_bits(priv->usb31misc, TCA_GCFG, + GCFG_ROLE_HSTDEV | GCFG_OP_MODE, + GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE); + if (ret) + goto out; + + ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG, + SYSMODE_CFG_TYPEC_DISABLE, 0); + if (ret) + goto out; + + ret = regmap_read(priv->usb31misc, TCA_TCPC, &val); + if (ret) + goto out; + val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK); + val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31); + ret = regmap_write(priv->usb31misc, TCA_TCPC, val); + if (ret) + goto out; + + ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL, + VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD); + if (ret) + goto out; + + return 0; +out: + dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); + return ret; +} + +static int hi3670_phy_init(struct phy *phy) +{ + struct hi3670_priv *priv = phy_get_drvdata(phy); + u32 val; + int ret; + + /* assert controller */ + val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET | + CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0); + if (ret) + goto out; + + ret = hi3670_config_phy_clock(priv); + if (ret) + goto out; + + /* Exit from IDDQ mode */ + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5, + CTRL5_USB2_SIDDQ, 0); + if (ret) + goto out; + + /* Release USB31 PHY out of TestPowerDown mode */ + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50, + CFG50_USB3_PHY_TEST_POWERDOWN, 0); + if (ret) + goto out; + + /* Deassert phy */ + val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); + if (ret) + goto out; + + usleep_range(100, 120); + + /* Tell the PHY power is stable */ + val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE | + CFG54_PHY0_PMA_PWR_STABLE; + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, + val, val); + if (ret) + goto out; + + ret = hi3670_config_tca(priv); + if (ret) + goto out; + + /* Enable SSC */ + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C, + CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN, + CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN); + if (ret) + goto out; + + /* Deassert controller */ + val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET; + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); + if (ret) + goto out; + + usleep_range(100, 120); + + /* Set fake vbus valid signal */ + val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL; + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val); + if (ret) + goto out; + + val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0; + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val); + if (ret) + goto out; + + usleep_range(100, 120); + + ret = hi3670_phy_set_params(priv); + if (ret) + goto out; + + return 0; +out: + dev_err(priv->dev, "failed to init phy ret: %d\n", ret); + return ret; +} + +static int hi3670_phy_exit(struct phy *phy) +{ + struct hi3670_priv *priv = phy_get_drvdata(phy); + u32 mask; + int ret; + + /* Assert phy */ + mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0); + if (ret) + goto out; + + if (hi3670_is_abbclk_seleted(priv)) { + /* disable usb_tcxo_en */ + ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, + USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START); + } else { + ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6, + GT_CLK_USB2PHY_REF); + if (ret) + goto out; + } + + return 0; +out: + dev_err(priv->dev, "failed to exit phy ret: %d\n", ret); + return ret; +} + +static struct phy_ops hi3670_phy_ops = { + .init = hi3670_phy_init, + .exit = hi3670_phy_exit, + .owner = THIS_MODULE, +}; + +static int hi3670_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct phy *phy; + struct hi3670_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node, + "hisilicon,pericrg-syscon"); + if (IS_ERR(priv->peri_crg)) { + dev_err(dev, "no hisilicon,pericrg-syscon\n"); + return PTR_ERR(priv->peri_crg); + } + + priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node, + "hisilicon,pctrl-syscon"); + if (IS_ERR(priv->pctrl)) { + dev_err(dev, "no hisilicon,pctrl-syscon\n"); + return PTR_ERR(priv->pctrl); + } + + priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node, + "hisilicon,sctrl-syscon"); + if (IS_ERR(priv->sctrl)) { + dev_err(dev, "no hisilicon,sctrl-syscon\n"); + return PTR_ERR(priv->sctrl); + } + + /* node of hi3670 phy is a sub-node of usb3_otg_bc */ + priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(priv->usb31misc)) { + dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n"); + return PTR_ERR(priv->usb31misc); + } + + if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param", + &priv->eye_diagram_param)) + priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM; + + if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl", + &priv->tx_vboost_lvl)) + priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST; + + phy = devm_phy_create(dev, NULL, &hi3670_phy_ops); + if (IS_ERR(phy)) + return PTR_ERR(phy); + + phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct of_device_id hi3670_phy_of_match[] = { + { .compatible = "hisilicon,hi3670-usb-phy" }, + { }, +}; +MODULE_DEVICE_TABLE(of, hi3670_phy_of_match); + +static struct platform_driver hi3670_phy_driver = { + .probe = hi3670_phy_probe, + .driver = { + .name = "hi3670-usb-phy", + .of_match_table = hi3670_phy_of_match, + } +}; +module_platform_driver(hi3670_phy_driver); + +MODULE_AUTHOR("Yu Chen "); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver"); diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index b29f5d5df134..0e97b5b9a56a 100644 --- a/drivers/staging/hikey9xx/Kconfig +++ b/drivers/staging/hikey9xx/Kconfig @@ -1,16 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -# to be placed at drivers/phy -config PHY_HI3670_USB - tristate "hi3670 USB PHY support" - depends on (ARCH_HISI && ARM64) || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the HISILICON HI3670 USB PHY. - - To compile this driver as a module, choose M here. - # to be placed at drivers/spmi config SPMI_HISI3670 tristate "Hisilicon 3670 SPMI Controller" diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile index 1924fadac952..9371dcc3d35b 100644 --- a/drivers/staging/hikey9xx/Makefile +++ b/drivers/staging/hikey9xx/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o - obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.c b/drivers/staging/hikey9xx/phy-hi3670-usb3.c deleted file mode 100644 index 4fc013911a78..000000000000 --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.c +++ /dev/null @@ -1,671 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform - * - * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd. - * http://www.huawei.com - * - * Authors: Yu Chen - */ - -#include -#include -#include -#include -#include -#include -#include - -#define SCTRL_SCDEEPSLEEPED (0x0) -#define USB_CLK_SELECTED BIT(20) - -#define PERI_CRG_PEREN0 (0x00) -#define PERI_CRG_PERDIS0 (0x04) -#define PERI_CRG_PEREN4 (0x40) -#define PERI_CRG_PERDIS4 (0x44) -#define PERI_CRG_PERRSTEN4 (0x90) -#define PERI_CRG_PERRSTDIS4 (0x94) -#define PERI_CRG_ISODIS (0x148) -#define PERI_CRG_PEREN6 (0x410) -#define PERI_CRG_PERDIS6 (0x414) - -#define USB_REFCLK_ISO_EN BIT(25) - -#define GT_CLK_USB2PHY_REF BIT(19) - -#define PCTRL_PERI_CTRL3 (0x10) -#define PCTRL_PERI_CTRL3_MSK_START (16) -#define USB_TCXO_EN BIT(1) - -#define PCTRL_PERI_CTRL24 (0x64) -#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25) - -#define USB3OTG_CTRL0 (0x00) -#define USB3OTG_CTRL3 (0x0C) -#define USB3OTG_CTRL4 (0x10) -#define USB3OTG_CTRL5 (0x14) -#define USB3OTG_CTRL7 (0x1C) -#define USB_MISC_CFG50 (0x50) -#define USB_MISC_CFG54 (0x54) -#define USB_MISC_CFG58 (0x58) -#define USB_MISC_CFG5C (0x5C) -#define USB_MISC_CFGA0 (0xA0) -#define TCA_CLK_RST (0x200) -#define TCA_INTR_EN (0x204) -#define TCA_INTR_STS (0x208) -#define TCA_GCFG (0x210) -#define TCA_TCPC (0x214) -#define TCA_SYSMODE_CFG (0x218) -#define TCA_VBUS_CTRL (0x240) - -#define CTRL0_USB3_VBUSVLD BIT(7) -#define CTRL0_USB3_VBUSVLD_SEL BIT(6) - -#define CTRL3_USB2_VBUSVLDEXT0 BIT(6) -#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5) - -#define CTRL5_USB2_SIDDQ BIT(0) - -#define CTRL7_USB2_REFCLKSEL_MASK (3 << 3) -#define CTRL7_USB2_REFCLKSEL_ABB (3 << 3) -#define CTRL7_USB2_REFCLKSEL_PAD (2 << 3) - -#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23) - -#define CFG54_USB31PHY_CR_ADDR_MASK (0xFFFF) -#define CFG54_USB31PHY_CR_ADDR_SHIFT (16) -#define CFG54_USB3PHY_REF_USE_PAD BIT(12) -#define CFG54_PHY0_PMA_PWR_STABLE BIT(11) -#define CFG54_PHY0_PCS_PWR_STABLE BIT(9) -#define CFG54_USB31PHY_CR_ACK BIT(7) -#define CFG54_USB31PHY_CR_WR_EN BIT(5) -#define CFG54_USB31PHY_CR_SEL BIT(4) -#define CFG54_USB31PHY_CR_RD_EN BIT(3) -#define CFG54_USB31PHY_CR_CLK BIT(2) -#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1) - -#define CFG58_USB31PHY_CR_DATA_MASK (0xFFFF) -#define CFG58_USB31PHY_CR_DATA_RD_START (16) - -#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1) - -#define CFGA0_VAUX_RESET BIT(9) -#define CFGA0_USB31C_RESET BIT(8) -#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4) -#define CFGA0_USB3PHY_RESET BIT(1) -#define CFGA0_USB2PHY_POR BIT(0) - -#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1) -#define INTR_EN_XA_ACK_EVT_EN BIT(0) - -#define CLK_RST_TCA_REF_CLK_EN BIT(1) -#define CLK_RST_SUSPEND_CLK_EN BIT(0) - -#define GCFG_ROLE_HSTDEV BIT(4) -#define GCFG_OP_MODE (3 << 0) -#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0) - -#define TCPC_VALID BIT(4) -#define TCPC_LOW_POWER_EN BIT(3) -#define TCPC_MUX_CONTROL_MASK (3 << 0) -#define TCPC_MUX_CONTROL_USB31 BIT(0) - -#define SYSMODE_CFG_TYPEC_DISABLE BIT(3) - -#define VBUS_CTRL_POWERPRESENT_OVERRD (3 << 2) -#define VBUS_CTRL_VBUSVALID_OVERRD (3 << 0) - -#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xFDFEE4) -#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5) - -#define TX_VBOOST_LVL_REG (0xf) -#define TX_VBOOST_LVL_START (6) -#define TX_VBOOST_LVL_ENABLE BIT(9) - -struct hi3670_priv { - struct device *dev; - struct regmap *peri_crg; - struct regmap *pctrl; - struct regmap *sctrl; - struct regmap *usb31misc; - - u32 eye_diagram_param; - u32 tx_vboost_lvl; - - u32 peri_crg_offset; - u32 pctrl_offset; - u32 usb31misc_offset; -}; - -static int hi3670_phy_cr_clk(struct regmap *usb31misc) -{ - int ret; - - /* Clock up */ - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK); - if (ret) - return ret; - - /* Clock down */ - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_CLK, 0); - - return ret; -} - -static int hi3670_phy_cr_set_sel(struct regmap *usb31misc) -{ - return regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL); -} - -static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction) -{ - int ret; - - if (direction) - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_WR_EN, - CFG54_USB31PHY_CR_WR_EN); - else - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_RD_EN, - CFG54_USB31PHY_CR_RD_EN); - - if (ret) - return ret; - - ret = hi3670_phy_cr_clk(usb31misc); - if (ret) - return ret; - - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, - CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0); - - return ret; -} - -static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc) -{ - u32 reg; - int retry = 100000; - int ret; - - while (retry-- > 0) { - ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); - if (ret) - return ret; - if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK) - return 0; - - ret = hi3670_phy_cr_clk(usb31misc); - if (ret) - return ret; - } - - return -ETIMEDOUT; -} - -static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr) -{ - u32 reg; - int ret; - - ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); - if (ret) - return ret; - - reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT); - reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT); - ret = regmap_write(usb31misc, USB_MISC_CFG54, reg); - - return ret; -} - -static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val) -{ - int reg; - int i; - int ret; - - for (i = 0; i < 100; i++) { - ret = hi3670_phy_cr_clk(usb31misc); - if (ret) - return ret; - } - - ret = hi3670_phy_cr_set_sel(usb31misc); - if (ret) - return ret; - - ret = hi3670_phy_cr_set_addr(usb31misc, addr); - if (ret) - return ret; - - ret = hi3670_phy_cr_start(usb31misc, 0); - if (ret) - return ret; - - ret = hi3670_phy_cr_wait_ack(usb31misc); - if (ret) - return ret; - - ret = regmap_read(usb31misc, USB_MISC_CFG58, ®); - if (ret) - return ret; - - *val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) & - CFG58_USB31PHY_CR_DATA_MASK; - - return 0; -} - -static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val) -{ - int i; - int ret; - - for (i = 0; i < 100; i++) { - ret = hi3670_phy_cr_clk(usb31misc); - if (ret) - return ret; - } - - ret = hi3670_phy_cr_set_sel(usb31misc); - if (ret) - return ret; - - ret = hi3670_phy_cr_set_addr(usb31misc, addr); - if (ret) - return ret; - - ret = regmap_write(usb31misc, USB_MISC_CFG58, - val & CFG58_USB31PHY_CR_DATA_MASK); - if (ret) - return ret; - - ret = hi3670_phy_cr_start(usb31misc, 1); - if (ret) - return ret; - - ret = hi3670_phy_cr_wait_ack(usb31misc); - - return ret; -} - -static int hi3670_phy_set_params(struct hi3670_priv *priv) -{ - u32 reg; - int ret; - int retry = 3; - - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4, - priv->eye_diagram_param); - if (ret) { - dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n"); - return ret; - } - - while (retry-- > 0) { - ret = hi3670_phy_cr_read(priv->usb31misc, - TX_VBOOST_LVL_REG, ®); - if (!ret) - break; - - if (ret != -ETIMEDOUT) { - dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n"); - return ret; - } - } - if (ret) - return ret; - - reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START)); - ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg); - if (ret) - dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n"); - - return ret; -} - -static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv) -{ - u32 reg; - - if (!priv->sctrl) { - dev_err(priv->dev, "priv->sctrl is null!\n"); - return 1; - } - - if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) { - dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n"); - return 1; - } - - if ((reg & USB_CLK_SELECTED) == 0) - return 1; - - return 0; -} - -static int hi3670_config_phy_clock(struct hi3670_priv *priv) -{ - u32 val, mask; - int ret; - - if (hi3670_is_abbclk_seleted(priv)) { - /* usb refclk iso disable */ - ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, - USB_REFCLK_ISO_EN); - if (ret) - goto out; - - /* enable usb_tcxo_en */ - ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, - USB_TCXO_EN | - (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START)); - - /* select usbphy clk from abb */ - mask = SC_CLK_USB3PHY_3MUX1_SEL; - ret = regmap_update_bits(priv->pctrl, - PCTRL_PERI_CTRL24, mask, 0); - if (ret) - goto out; - - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, - CFGA0_USB2PHY_REFCLK_SELECT, 0); - if (ret) - goto out; - - ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); - if (ret) - goto out; - val &= ~CTRL7_USB2_REFCLKSEL_MASK; - val |= CTRL7_USB2_REFCLKSEL_ABB; - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); - if (ret) - goto out; - - return 0; - } - - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, - CFG54_USB3PHY_REF_USE_PAD, - CFG54_USB3PHY_REF_USE_PAD); - if (ret) - goto out; - - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, - CFGA0_USB2PHY_REFCLK_SELECT, - CFGA0_USB2PHY_REFCLK_SELECT); - if (ret) - goto out; - - ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); - if (ret) - goto out; - val &= ~CTRL7_USB2_REFCLKSEL_MASK; - val |= CTRL7_USB2_REFCLKSEL_PAD; - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); - if (ret) - goto out; - - ret = regmap_write(priv->peri_crg, - PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF); - if (ret) - goto out; - - return 0; -out: - dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); - return ret; -} - -static int hi3670_config_tca(struct hi3670_priv *priv) -{ - u32 val, mask; - int ret; - - ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff); - if (ret) - goto out; - - ret = regmap_write(priv->usb31misc, TCA_INTR_EN, - INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN); - if (ret) - goto out; - - mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN; - ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0); - if (ret) - goto out; - - ret = regmap_update_bits(priv->usb31misc, TCA_GCFG, - GCFG_ROLE_HSTDEV | GCFG_OP_MODE, - GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE); - if (ret) - goto out; - - ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG, - SYSMODE_CFG_TYPEC_DISABLE, 0); - if (ret) - goto out; - - ret = regmap_read(priv->usb31misc, TCA_TCPC, &val); - if (ret) - goto out; - val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK); - val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31); - ret = regmap_write(priv->usb31misc, TCA_TCPC, val); - if (ret) - goto out; - - ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL, - VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD); - if (ret) - goto out; - - return 0; -out: - dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); - return ret; -} - -static int hi3670_phy_init(struct phy *phy) -{ - struct hi3670_priv *priv = phy_get_drvdata(phy); - u32 val; - int ret; - - /* assert controller */ - val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET | - CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0); - if (ret) - goto out; - - ret = hi3670_config_phy_clock(priv); - if (ret) - goto out; - - /* Exit from IDDQ mode */ - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5, - CTRL5_USB2_SIDDQ, 0); - if (ret) - goto out; - - /* Release USB31 PHY out of TestPowerDown mode */ - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50, - CFG50_USB3_PHY_TEST_POWERDOWN, 0); - if (ret) - goto out; - - /* Deassert phy */ - val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); - if (ret) - goto out; - - usleep_range(100, 120); - - /* Tell the PHY power is stable */ - val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE | - CFG54_PHY0_PMA_PWR_STABLE; - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, - val, val); - if (ret) - goto out; - - ret = hi3670_config_tca(priv); - if (ret) - goto out; - - /* Enable SSC */ - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C, - CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN, - CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN); - if (ret) - goto out; - - /* Deassert controller */ - val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET; - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); - if (ret) - goto out; - - usleep_range(100, 120); - - /* Set fake vbus valid signal */ - val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL; - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val); - if (ret) - goto out; - - val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0; - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val); - if (ret) - goto out; - - usleep_range(100, 120); - - ret = hi3670_phy_set_params(priv); - if (ret) - goto out; - - return 0; -out: - dev_err(priv->dev, "failed to init phy ret: %d\n", ret); - return ret; -} - -static int hi3670_phy_exit(struct phy *phy) -{ - struct hi3670_priv *priv = phy_get_drvdata(phy); - u32 mask; - int ret; - - /* Assert phy */ - mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0); - if (ret) - goto out; - - if (hi3670_is_abbclk_seleted(priv)) { - /* disable usb_tcxo_en */ - ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, - USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START); - } else { - ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6, - GT_CLK_USB2PHY_REF); - if (ret) - goto out; - } - - return 0; -out: - dev_err(priv->dev, "failed to exit phy ret: %d\n", ret); - return ret; -} - -static struct phy_ops hi3670_phy_ops = { - .init = hi3670_phy_init, - .exit = hi3670_phy_exit, - .owner = THIS_MODULE, -}; - -static int hi3670_phy_probe(struct platform_device *pdev) -{ - struct phy_provider *phy_provider; - struct device *dev = &pdev->dev; - struct phy *phy; - struct hi3670_priv *priv; - - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->dev = dev; - priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node, - "hisilicon,pericrg-syscon"); - if (IS_ERR(priv->peri_crg)) { - dev_err(dev, "no hisilicon,pericrg-syscon\n"); - return PTR_ERR(priv->peri_crg); - } - - priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node, - "hisilicon,pctrl-syscon"); - if (IS_ERR(priv->pctrl)) { - dev_err(dev, "no hisilicon,pctrl-syscon\n"); - return PTR_ERR(priv->pctrl); - } - - priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node, - "hisilicon,sctrl-syscon"); - if (IS_ERR(priv->sctrl)) { - dev_err(dev, "no hisilicon,sctrl-syscon\n"); - return PTR_ERR(priv->sctrl); - } - - /* node of hi3670 phy is a sub-node of usb3_otg_bc */ - priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node); - if (IS_ERR(priv->usb31misc)) { - dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n"); - return PTR_ERR(priv->usb31misc); - } - - if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param", - &priv->eye_diagram_param)) - priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM; - - if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl", - &priv->tx_vboost_lvl)) - priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST; - - phy = devm_phy_create(dev, NULL, &hi3670_phy_ops); - if (IS_ERR(phy)) - return PTR_ERR(phy); - - phy_set_drvdata(phy, priv); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - return PTR_ERR_OR_ZERO(phy_provider); -} - -static const struct of_device_id hi3670_phy_of_match[] = { - { .compatible = "hisilicon,hi3670-usb-phy" }, - { }, -}; -MODULE_DEVICE_TABLE(of, hi3670_phy_of_match); - -static struct platform_driver hi3670_phy_driver = { - .probe = hi3670_phy_probe, - .driver = { - .name = "hi3670-usb-phy", - .of_match_table = hi3670_phy_of_match, - } -}; -module_platform_driver(hi3670_phy_driver); - -MODULE_AUTHOR("Yu Chen "); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver"); diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml b/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml deleted file mode 100644 index 125a5d6546ae..000000000000 --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Hisilicon Kirin970 USB PHY - -maintainers: - - Mauro Carvalho Chehab -description: |+ - Bindings for USB3 PHY on HiSilicon Kirin 970. - -properties: - compatible: - const: hisilicon,hi3670-usb-phy - - "#phy-cells": - const: 0 - - hisilicon,pericrg-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' - description: phandle of syscon used to control iso refclk. - - hisilicon,pctrl-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' - description: phandle of syscon used to control usb tcxo. - - hisilicon,sctrl-syscon: - $ref: '/schemas/types.yaml#/definitions/phandle' - description: phandle of syscon used to control phy deep sleep. - - hisilicon,eye-diagram-param: - $ref: /schemas/types.yaml#/definitions/uint32 - description: Eye diagram for phy. - - hisilicon,tx-vboost-lvl: - $ref: /schemas/types.yaml#/definitions/uint32 - description: TX level vboost for phy. - -required: - - compatible - - hisilicon,pericrg-syscon - - hisilicon,pctrl-syscon - - hisilicon,sctrl-syscon - - hisilicon,eye-diagram-param - - hisilicon,tx-vboost-lvl - - "#phy-cells" - -additionalProperties: false - -examples: - - | - bus { - #address-cells = <2>; - #size-cells = <2>; - - usb3_otg_bc: usb3_otg_bc at ff200000 { - compatible = "syscon", "simple-mfd"; - reg = <0x0 0xff200000 0x0 0x1000>; - - usb_phy { - compatible = "hisilicon,hi3670-usb-phy"; - #phy-cells = <0>; - hisilicon,pericrg-syscon = <&crg_ctrl>; - hisilicon,pctrl-syscon = <&pctrl>; - hisilicon,sctrl-syscon = <&sctrl>; - hisilicon,eye-diagram-param = <0xfdfee4>; - hisilicon,tx-vboost-lvl = <0x5>; - }; - }; - }; -- 2.28.0 From m.cerveny at computer.org Mon Nov 16 12:56:17 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:17 +0100 Subject: [PATCH v3 6/6] ARM: dts: sun8i: v3s: Add video engine node In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-7-m.cerveny@computer.org> Allwinner V3S SoC has a video engine. Add a node for it. Signed-off-by: Martin Cerveny --- arch/arm/boot/dts/sun8i-v3s.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index 70193512c222..e8f304125e2d 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -211,6 +211,16 @@ tcon0_out: port at 1 { }; }; + video-codec at 1c0e000 { + compatible = "allwinner,sun8i-v3s-video-engine"; + reg = <0x01c0e000 0x1000>; + clocks = <&ccu CLK_BUS_VE>, <&ccu CLK_VE>, + <&ccu CLK_DRAM_VE>; + clock-names = "ahb", "mod", "ram"; + resets = <&ccu RST_BUS_VE>; + interrupts = ; + allwinner,sram = <&ve_sram 1>; + }; mmc0: mmc at 1c0f000 { compatible = "allwinner,sun7i-a20-mmc"; -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:14 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:14 +0100 Subject: [PATCH v3 3/6] ARM: dts: sun8i: v3s: Add node for system control In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-4-m.cerveny@computer.org> Allwinner V3s has system control and SRAM C1 region similar to H3. Signed-off-by: Martin Cerveny --- arch/arm/boot/dts/sun8i-v3s.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index 0c7341676921..70193512c222 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -161,6 +161,20 @@ syscon: system-control at 1c00000 { #address-cells = <1>; #size-cells = <1>; ranges; + + sram_c: sram at 1d00000 { + compatible = "mmio-sram"; + reg = <0x01d00000 0x80000>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0 0x01d00000 0x80000>; + + ve_sram: sram-section at 0 { + compatible = "allwinner,sun8i-v3s-sram-c1", + "allwinner,sun4i-a10-sram-c1"; + reg = <0x000000 0x80000>; + }; + }; }; tcon0: lcd-controller at 1c0c000 { -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:16 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:16 +0100 Subject: [PATCH v3 5/6] dt-bindings: media: cedrus: Add V3s compatible In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-6-m.cerveny@computer.org> Allwinner V3s SoC contains video engine. Add compatible for it. Signed-off-by: Martin Cerveny --- .../bindings/media/allwinner,sun4i-a10-video-engine.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml index 0d58bbcd24d3..2f7058f7760c 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun4i-a10-video-engine.yaml @@ -18,6 +18,7 @@ properties: - allwinner,sun7i-a20-video-engine - allwinner,sun8i-a33-video-engine - allwinner,sun8i-h3-video-engine + - allwinner,sun8i-v3s-video-engine - allwinner,sun8i-r40-video-engine - allwinner,sun50i-a64-video-engine - allwinner,sun50i-h5-video-engine -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:13 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:13 +0100 Subject: [PATCH v3 2/6] dt-bindings: sram: allwinner, sun4i-a10-system-control: Add V3s compatibles In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-3-m.cerveny@computer.org> Allwinner V3s has system control similar to that in H3. Add compatibles for system control with SRAM C1 region. Signed-off-by: Martin Cerveny --- .../bindings/sram/allwinner,sun4i-a10-system-control.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml index b66a07e21d1e..bdd352b01434 100644 --- a/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml +++ b/Documentation/devicetree/bindings/sram/allwinner,sun4i-a10-system-control.yaml @@ -92,6 +92,9 @@ patternProperties: - items: - const: allwinner,sun8i-h3-sram-c1 - const: allwinner,sun4i-a10-sram-c1 + - items: + - const: allwinner,sun8i-v3s-sram-c1 + - const: allwinner,sun4i-a10-sram-c1 - items: - const: allwinner,sun8i-r40-sram-c1 - const: allwinner,sun4i-a10-sram-c1 -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:15 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:15 +0100 Subject: [PATCH v3 4/6] media: cedrus: Add support for V3s In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-5-m.cerveny@computer.org> V3s video engine runs at lower speed and support video decoder for H.264 and JPEG/MJPEG only. Signed-off-by: Martin Cerveny --- drivers/staging/media/sunxi/cedrus/cedrus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 3487554fab68..ee4e21b29374 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -518,6 +518,12 @@ static const struct cedrus_variant sun8i_h3_cedrus_variant = { .mod_rate = 402000000, }; +static const struct cedrus_variant sun8i_v3s_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_H264_DEC, + .mod_rate = 297000000, +}; + static const struct cedrus_variant sun8i_r40_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | CEDRUS_CAPABILITY_MPEG2_DEC | @@ -571,6 +577,10 @@ static const struct of_device_id cedrus_dt_match[] = { .compatible = "allwinner,sun8i-h3-video-engine", .data = &sun8i_h3_cedrus_variant, }, + { + .compatible = "allwinner,sun8i-v3s-video-engine", + .data = &sun8i_v3s_cedrus_variant, + }, { .compatible = "allwinner,sun8i-r40-video-engine", .data = &sun8i_r40_cedrus_variant, -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:11 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:11 +0100 Subject: [PATCH v3 0/6] ARM: dts: sun8i: v3s: Enable video decoder Message-ID: <20201116125617.7597-1-m.cerveny@computer.org> First patch extends cedrus capability to all decoders because V3s missing MPEG2 decoder. Next two patches add system control node (SRAM C1) and next three patches add support for Cedrus VPU. Tested on "Lichee Zero" V3s platform with testing LCD patch ( https://github.com/mcerveny/linux/tree/media_tree_for-v5.11e ) and V4L2 raw API testing utility (updated to v5.10) ( https://github.com/mcerveny/v4l2-request-test ): - enabled LCD (DRM dual VI and sigle UI planes) - added RGB panel - enabled PWM - need additional patch https://git.linuxtv.org/media_tree.git/commit/?h=fixes&id=9ac924b98728c3733c91c6c59fc410827d0da49f There is low memory on V3s (64MB) and maximum must be available to CMA: - CONFIG_CMA_SIZE_MBYTES=28 - add swap to swapout other processes - decrease buffers in v4l2-request-test (.buffers_count from 16 to 8) Only H.264 decoder working - MPEG and H.265 unsupported by V3s, JPEG/MJPEG still unimplemented, encoder unimplemented best regards, Martin Changes since v2: - updated/rebased to https://git.linuxtv.org/hverkuil/media_tree.git/?h=for-v5.11e - some parts of patches implemeted by others - updated R40 Changes since v1: - patch 0005 rename - added testing description Martin Cerveny (6): media: cedrus: Register all codecs as capability dt-bindings: sram: allwinner,sun4i-a10-system-control: Add V3s compatibles ARM: dts: sun8i: v3s: Add node for system control media: cedrus: Add support for V3s dt-bindings: media: cedrus: Add V3s compatible ARM: dts: sun8i: v3s: Add video engine node .../allwinner,sun4i-a10-video-engine.yaml | 1 + .../allwinner,sun4i-a10-system-control.yaml | 3 ++ arch/arm/boot/dts/sun8i-v3s.dtsi | 24 ++++++++++++++ drivers/staging/media/sunxi/cedrus/cedrus.c | 32 +++++++++++++++++-- drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ 6 files changed, 62 insertions(+), 2 deletions(-) -- 2.25.1 From m.cerveny at computer.org Mon Nov 16 12:56:12 2020 From: m.cerveny at computer.org (Martin Cerveny) Date: Mon, 16 Nov 2020 13:56:12 +0100 Subject: [PATCH v3 1/6] media: cedrus: Register all codecs as capability In-Reply-To: <20201116125617.7597-1-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> Message-ID: <20201116125617.7597-2-m.cerveny@computer.org> All codecs should have capabilities. For example "Allwinner V3s" does not support "MPEG2". Signed-off-by: Martin Cerveny --- drivers/staging/media/sunxi/cedrus/cedrus.c | 22 +++++++++++++++++-- drivers/staging/media/sunxi/cedrus/cedrus.h | 2 ++ .../staging/media/sunxi/cedrus/cedrus_video.c | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index 9a102b7c1bb9..3487554fab68 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -486,47 +486,65 @@ static int cedrus_remove(struct platform_device *pdev) } static const struct cedrus_variant sun4i_a10_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun5i_a13_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun7i_a20_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_a33_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 320000000, }; static const struct cedrus_variant sun8i_h3_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun8i_r40_cedrus_variant = { - .capabilities = CEDRUS_CAPABILITY_UNTILED, + .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC, .mod_rate = 297000000, }; static const struct cedrus_variant sun50i_a64_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h5_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .mod_rate = 402000000, }; static const struct cedrus_variant sun50i_h6_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED | + CEDRUS_CAPABILITY_MPEG2_DEC | + CEDRUS_CAPABILITY_H264_DEC | CEDRUS_CAPABILITY_H265_DEC, .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, .mod_rate = 600000000, diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 93c843ae14bb..30cdb15d6800 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -28,6 +28,8 @@ #define CEDRUS_CAPABILITY_UNTILED BIT(0) #define CEDRUS_CAPABILITY_H265_DEC BIT(1) +#define CEDRUS_CAPABILITY_H264_DEC BIT(2) +#define CEDRUS_CAPABILITY_MPEG2_DEC BIT(3) #define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index 911f607d9b09..bdca23fc214b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -38,10 +38,12 @@ static struct cedrus_format cedrus_formats[] = { { .pixelformat = V4L2_PIX_FMT_MPEG2_SLICE, .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_MPEG2_DEC, }, { .pixelformat = V4L2_PIX_FMT_H264_SLICE, .directions = CEDRUS_DECODE_SRC, + .capabilities = CEDRUS_CAPABILITY_H264_DEC, }, { .pixelformat = V4L2_PIX_FMT_HEVC_SLICE, -- 2.25.1 From broonie at kernel.org Mon Nov 16 13:33:11 2020 From: broonie at kernel.org (Mark Brown) Date: Mon, 16 Nov 2020 13:33:11 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <74cfc6a9-3f59-d679-14b7-51102a6f11b3@gmail.com> References: <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> <20201113172859.GF4828@sirena.org.uk> <74cfc6a9-3f59-d679-14b7-51102a6f11b3@gmail.com> Message-ID: <20201116133311.GB4739@sirena.org.uk> On Sun, Nov 15, 2020 at 08:42:10PM +0300, Dmitry Osipenko wrote: > 13.11.2020 20:28, Mark Brown ?????: > >> What should we do? > > As I keep saying the consumer driver should be enumerating the voltages > > it can set, if it can't find any and wants to continue then it can just > > skip setting voltages later on. If only some are unavailable then it > > probably wants to eliminate those specific OPPs instead. > I'm seeing a dummy regulator as a helper for consumer drivers which > removes burden of handling an absent (optional) regulator. Is this a > correct understanding of a dummy regulator? > Older DTBs don't have a regulator and we want to keep them working. This > is equal to a physically absent regulator and in this case it's an > optional regulator, IMO. No, you are failing to understand the purpose of this code. To reiterate unless the device supports operating with the supply physically absent then the driver should not be attempting to use regulator_get_optional(). That exists specifically for the case where the supply may be absent, nothing else. The dummy regulator is there precisely for the case where the system does not describe supplies that we know are required for the device to function, it fixes up that omission so we don't need to open code handling of this in every single consumer driver. Regulators that are present but not described by the firmware are a clearly different case to regulators that are not physically there, hardware with actually optional regulators will generally require some configuration for this case. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From robh at kernel.org Mon Nov 16 15:31:06 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 16 Nov 2020 09:31:06 -0600 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> References: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201116153106.GA1682049@bogus> On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote: > The phy USB3 driver for Hisilicon 970 (hi3670) is ready > for mainstream. Mode it from staging into the main driver's s/Mode/Move/ > phy/ directory. > > Signed-off-by: Mauro Carvalho Chehab > --- > .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ > MAINTAINERS | 9 +- > drivers/phy/hisilicon/Kconfig | 10 + > drivers/phy/hisilicon/Makefile | 1 + > drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ > drivers/staging/hikey9xx/Kconfig | 11 - > drivers/staging/hikey9xx/Makefile | 2 - > drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ > drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- I assume this is only a move? Use '-M' option. > 9 files changed, 762 insertions(+), 757 deletions(-) > create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml > create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c > delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c > delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml > > diff --git a/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml > new file mode 100644 > index 000000000000..125a5d6546ae > --- /dev/null > +++ b/Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml > @@ -0,0 +1,72 @@ > +# SPDX-License-Identifier: GPL-2.0 > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: Hisilicon Kirin970 USB PHY > + > +maintainers: > + - Mauro Carvalho Chehab > +description: |+ > + Bindings for USB3 PHY on HiSilicon Kirin 970. > + > +properties: > + compatible: > + const: hisilicon,hi3670-usb-phy > + > + "#phy-cells": > + const: 0 > + > + hisilicon,pericrg-syscon: > + $ref: '/schemas/types.yaml#/definitions/phandle' > + description: phandle of syscon used to control iso refclk. > + > + hisilicon,pctrl-syscon: > + $ref: '/schemas/types.yaml#/definitions/phandle' > + description: phandle of syscon used to control usb tcxo. > + > + hisilicon,sctrl-syscon: > + $ref: '/schemas/types.yaml#/definitions/phandle' > + description: phandle of syscon used to control phy deep sleep. > + > + hisilicon,eye-diagram-param: > + $ref: /schemas/types.yaml#/definitions/uint32 > + description: Eye diagram for phy. > + > + hisilicon,tx-vboost-lvl: > + $ref: /schemas/types.yaml#/definitions/uint32 > + description: TX level vboost for phy. > + > +required: > + - compatible > + - hisilicon,pericrg-syscon > + - hisilicon,pctrl-syscon > + - hisilicon,sctrl-syscon > + - hisilicon,eye-diagram-param > + - hisilicon,tx-vboost-lvl > + - "#phy-cells" > + > +additionalProperties: false > + > +examples: > + - | > + bus { > + #address-cells = <2>; > + #size-cells = <2>; > + > + usb3_otg_bc: usb3_otg_bc at ff200000 { > + compatible = "syscon", "simple-mfd"; > + reg = <0x0 0xff200000 0x0 0x1000>; > + > + usb_phy { > + compatible = "hisilicon,hi3670-usb-phy"; > + #phy-cells = <0>; > + hisilicon,pericrg-syscon = <&crg_ctrl>; > + hisilicon,pctrl-syscon = <&pctrl>; > + hisilicon,sctrl-syscon = <&sctrl>; > + hisilicon,eye-diagram-param = <0xfdfee4>; > + hisilicon,tx-vboost-lvl = <0x5>; > + }; > + }; > + }; > diff --git a/MAINTAINERS b/MAINTAINERS > index e451dcce054f..14266bb79ff8 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -18083,7 +18083,7 @@ L: linux-usb at vger.kernel.org > S: Maintained > F: drivers/usb/roles/intel-xhci-usb-role-switch.c > > -USB IP DRIVER FOR HISILICON KIRIN > +USB IP DRIVER FOR HISILICON KIRIN 960 > M: Yu Chen > M: Binghui Wang > L: linux-usb at vger.kernel.org > @@ -18091,6 +18091,13 @@ S: Maintained > F: Documentation/devicetree/bindings/phy/hisilicon,hi3660-usb3.yaml > F: drivers/phy/hisilicon/phy-hi3660-usb3.c > > +USB IP DRIVER FOR HISILICON KIRIN 970 > +M: Mauro Carvalho Chehab > +L: linux-usb at vger.kernel.org > +S: Maintained > +F: Documentation/devicetree/bindings/phy/hisilicon,kirin970-usb3.yaml > +F: drivers/phy/hisilicon/phy-kirin970-usb3.c > + > USB ISP116X DRIVER > M: Olav Kongas > L: linux-usb at vger.kernel.org > diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig > index 1c73053bcc98..4d008cfc279c 100644 > --- a/drivers/phy/hisilicon/Kconfig > +++ b/drivers/phy/hisilicon/Kconfig > @@ -23,6 +23,16 @@ config PHY_HI3660_USB > > To compile this driver as a module, choose M here. > > +config PHY_HI3670_USB > + tristate "hi3670 USB PHY support" > + depends on (ARCH_HISI && ARM64) || COMPILE_TEST > + select GENERIC_PHY > + select MFD_SYSCON > + help > + Enable this to support the HISILICON HI3670 USB PHY. > + > + To compile this driver as a module, choose M here. > + > config PHY_HISTB_COMBPHY > tristate "HiSilicon STB SoCs COMBPHY support" > depends on (ARCH_HISI && ARM64) || COMPILE_TEST > diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile > index 92e874ae9c74..51729868145b 100644 > --- a/drivers/phy/hisilicon/Makefile > +++ b/drivers/phy/hisilicon/Makefile > @@ -1,6 +1,7 @@ > # SPDX-License-Identifier: GPL-2.0-only > obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o > obj-$(CONFIG_PHY_HI3660_USB) += phy-hi3660-usb3.o > +obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o > obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o > obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o > obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o > diff --git a/drivers/phy/hisilicon/phy-hi3670-usb3.c b/drivers/phy/hisilicon/phy-hi3670-usb3.c > new file mode 100644 > index 000000000000..4fc013911a78 > --- /dev/null > +++ b/drivers/phy/hisilicon/phy-hi3670-usb3.c > @@ -0,0 +1,671 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform > + * > + * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd. > + * http://www.huawei.com > + * > + * Authors: Yu Chen > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#define SCTRL_SCDEEPSLEEPED (0x0) > +#define USB_CLK_SELECTED BIT(20) > + > +#define PERI_CRG_PEREN0 (0x00) > +#define PERI_CRG_PERDIS0 (0x04) > +#define PERI_CRG_PEREN4 (0x40) > +#define PERI_CRG_PERDIS4 (0x44) > +#define PERI_CRG_PERRSTEN4 (0x90) > +#define PERI_CRG_PERRSTDIS4 (0x94) > +#define PERI_CRG_ISODIS (0x148) > +#define PERI_CRG_PEREN6 (0x410) > +#define PERI_CRG_PERDIS6 (0x414) > + > +#define USB_REFCLK_ISO_EN BIT(25) > + > +#define GT_CLK_USB2PHY_REF BIT(19) > + > +#define PCTRL_PERI_CTRL3 (0x10) > +#define PCTRL_PERI_CTRL3_MSK_START (16) > +#define USB_TCXO_EN BIT(1) > + > +#define PCTRL_PERI_CTRL24 (0x64) > +#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25) > + > +#define USB3OTG_CTRL0 (0x00) > +#define USB3OTG_CTRL3 (0x0C) > +#define USB3OTG_CTRL4 (0x10) > +#define USB3OTG_CTRL5 (0x14) > +#define USB3OTG_CTRL7 (0x1C) > +#define USB_MISC_CFG50 (0x50) > +#define USB_MISC_CFG54 (0x54) > +#define USB_MISC_CFG58 (0x58) > +#define USB_MISC_CFG5C (0x5C) > +#define USB_MISC_CFGA0 (0xA0) > +#define TCA_CLK_RST (0x200) > +#define TCA_INTR_EN (0x204) > +#define TCA_INTR_STS (0x208) > +#define TCA_GCFG (0x210) > +#define TCA_TCPC (0x214) > +#define TCA_SYSMODE_CFG (0x218) > +#define TCA_VBUS_CTRL (0x240) > + > +#define CTRL0_USB3_VBUSVLD BIT(7) > +#define CTRL0_USB3_VBUSVLD_SEL BIT(6) > + > +#define CTRL3_USB2_VBUSVLDEXT0 BIT(6) > +#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5) > + > +#define CTRL5_USB2_SIDDQ BIT(0) > + > +#define CTRL7_USB2_REFCLKSEL_MASK (3 << 3) > +#define CTRL7_USB2_REFCLKSEL_ABB (3 << 3) > +#define CTRL7_USB2_REFCLKSEL_PAD (2 << 3) > + > +#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23) > + > +#define CFG54_USB31PHY_CR_ADDR_MASK (0xFFFF) > +#define CFG54_USB31PHY_CR_ADDR_SHIFT (16) > +#define CFG54_USB3PHY_REF_USE_PAD BIT(12) > +#define CFG54_PHY0_PMA_PWR_STABLE BIT(11) > +#define CFG54_PHY0_PCS_PWR_STABLE BIT(9) > +#define CFG54_USB31PHY_CR_ACK BIT(7) > +#define CFG54_USB31PHY_CR_WR_EN BIT(5) > +#define CFG54_USB31PHY_CR_SEL BIT(4) > +#define CFG54_USB31PHY_CR_RD_EN BIT(3) > +#define CFG54_USB31PHY_CR_CLK BIT(2) > +#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1) > + > +#define CFG58_USB31PHY_CR_DATA_MASK (0xFFFF) > +#define CFG58_USB31PHY_CR_DATA_RD_START (16) > + > +#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1) > + > +#define CFGA0_VAUX_RESET BIT(9) > +#define CFGA0_USB31C_RESET BIT(8) > +#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4) > +#define CFGA0_USB3PHY_RESET BIT(1) > +#define CFGA0_USB2PHY_POR BIT(0) > + > +#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1) > +#define INTR_EN_XA_ACK_EVT_EN BIT(0) > + > +#define CLK_RST_TCA_REF_CLK_EN BIT(1) > +#define CLK_RST_SUSPEND_CLK_EN BIT(0) > + > +#define GCFG_ROLE_HSTDEV BIT(4) > +#define GCFG_OP_MODE (3 << 0) > +#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0) > + > +#define TCPC_VALID BIT(4) > +#define TCPC_LOW_POWER_EN BIT(3) > +#define TCPC_MUX_CONTROL_MASK (3 << 0) > +#define TCPC_MUX_CONTROL_USB31 BIT(0) > + > +#define SYSMODE_CFG_TYPEC_DISABLE BIT(3) > + > +#define VBUS_CTRL_POWERPRESENT_OVERRD (3 << 2) > +#define VBUS_CTRL_VBUSVALID_OVERRD (3 << 0) > + > +#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xFDFEE4) > +#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5) > + > +#define TX_VBOOST_LVL_REG (0xf) > +#define TX_VBOOST_LVL_START (6) > +#define TX_VBOOST_LVL_ENABLE BIT(9) > + > +struct hi3670_priv { > + struct device *dev; > + struct regmap *peri_crg; > + struct regmap *pctrl; > + struct regmap *sctrl; > + struct regmap *usb31misc; > + > + u32 eye_diagram_param; > + u32 tx_vboost_lvl; > + > + u32 peri_crg_offset; > + u32 pctrl_offset; > + u32 usb31misc_offset; > +}; > + > +static int hi3670_phy_cr_clk(struct regmap *usb31misc) > +{ > + int ret; > + > + /* Clock up */ > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK); > + if (ret) > + return ret; > + > + /* Clock down */ > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_CLK, 0); > + > + return ret; > +} > + > +static int hi3670_phy_cr_set_sel(struct regmap *usb31misc) > +{ > + return regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL); > +} > + > +static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction) > +{ > + int ret; > + > + if (direction) > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_WR_EN, > + CFG54_USB31PHY_CR_WR_EN); > + else > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_RD_EN, > + CFG54_USB31PHY_CR_RD_EN); > + > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; > + > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0); > + > + return ret; > +} > + > +static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc) > +{ > + u32 reg; > + int retry = 100000; > + int ret; > + > + while (retry-- > 0) { > + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > + if (ret) > + return ret; > + if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK) > + return 0; > + > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; > + } > + > + return -ETIMEDOUT; > +} > + > +static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr) > +{ > + u32 reg; > + int ret; > + > + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > + if (ret) > + return ret; > + > + reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT); > + reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT); > + ret = regmap_write(usb31misc, USB_MISC_CFG54, reg); > + > + return ret; > +} > + > +static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val) > +{ > + int reg; > + int i; > + int ret; > + > + for (i = 0; i < 100; i++) { > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; > + } > + > + ret = hi3670_phy_cr_set_sel(usb31misc); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_set_addr(usb31misc, addr); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_start(usb31misc, 0); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_wait_ack(usb31misc); > + if (ret) > + return ret; > + > + ret = regmap_read(usb31misc, USB_MISC_CFG58, ®); > + if (ret) > + return ret; > + > + *val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) & > + CFG58_USB31PHY_CR_DATA_MASK; > + > + return 0; > +} > + > +static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val) > +{ > + int i; > + int ret; > + > + for (i = 0; i < 100; i++) { > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; > + } > + > + ret = hi3670_phy_cr_set_sel(usb31misc); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_set_addr(usb31misc, addr); > + if (ret) > + return ret; > + > + ret = regmap_write(usb31misc, USB_MISC_CFG58, > + val & CFG58_USB31PHY_CR_DATA_MASK); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_start(usb31misc, 1); > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_wait_ack(usb31misc); > + > + return ret; > +} > + > +static int hi3670_phy_set_params(struct hi3670_priv *priv) > +{ > + u32 reg; > + int ret; > + int retry = 3; > + > + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4, > + priv->eye_diagram_param); > + if (ret) { > + dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n"); > + return ret; > + } > + > + while (retry-- > 0) { > + ret = hi3670_phy_cr_read(priv->usb31misc, > + TX_VBOOST_LVL_REG, ®); > + if (!ret) > + break; > + > + if (ret != -ETIMEDOUT) { > + dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n"); > + return ret; > + } > + } > + if (ret) > + return ret; > + > + reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START)); > + ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg); > + if (ret) > + dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n"); > + > + return ret; > +} > + > +static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv) > +{ > + u32 reg; > + > + if (!priv->sctrl) { > + dev_err(priv->dev, "priv->sctrl is null!\n"); > + return 1; > + } > + > + if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) { > + dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n"); > + return 1; > + } > + > + if ((reg & USB_CLK_SELECTED) == 0) > + return 1; > + > + return 0; > +} > + > +static int hi3670_config_phy_clock(struct hi3670_priv *priv) > +{ > + u32 val, mask; > + int ret; > + > + if (hi3670_is_abbclk_seleted(priv)) { > + /* usb refclk iso disable */ > + ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, > + USB_REFCLK_ISO_EN); > + if (ret) > + goto out; > + > + /* enable usb_tcxo_en */ > + ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, > + USB_TCXO_EN | > + (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START)); > + > + /* select usbphy clk from abb */ > + mask = SC_CLK_USB3PHY_3MUX1_SEL; > + ret = regmap_update_bits(priv->pctrl, > + PCTRL_PERI_CTRL24, mask, 0); > + if (ret) > + goto out; > + > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, > + CFGA0_USB2PHY_REFCLK_SELECT, 0); > + if (ret) > + goto out; > + > + ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); > + if (ret) > + goto out; > + val &= ~CTRL7_USB2_REFCLKSEL_MASK; > + val |= CTRL7_USB2_REFCLKSEL_ABB; > + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); > + if (ret) > + goto out; > + > + return 0; > + } > + > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, > + CFG54_USB3PHY_REF_USE_PAD, > + CFG54_USB3PHY_REF_USE_PAD); > + if (ret) > + goto out; > + > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, > + CFGA0_USB2PHY_REFCLK_SELECT, > + CFGA0_USB2PHY_REFCLK_SELECT); > + if (ret) > + goto out; > + > + ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); > + if (ret) > + goto out; > + val &= ~CTRL7_USB2_REFCLKSEL_MASK; > + val |= CTRL7_USB2_REFCLKSEL_PAD; > + ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); > + if (ret) > + goto out; > + > + ret = regmap_write(priv->peri_crg, > + PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF); > + if (ret) > + goto out; > + > + return 0; > +out: > + dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); > + return ret; > +} > + > +static int hi3670_config_tca(struct hi3670_priv *priv) > +{ > + u32 val, mask; > + int ret; > + > + ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff); > + if (ret) > + goto out; > + > + ret = regmap_write(priv->usb31misc, TCA_INTR_EN, > + INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN); > + if (ret) > + goto out; > + > + mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN; > + ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0); > + if (ret) > + goto out; > + > + ret = regmap_update_bits(priv->usb31misc, TCA_GCFG, > + GCFG_ROLE_HSTDEV | GCFG_OP_MODE, > + GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE); > + if (ret) > + goto out; > + > + ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG, > + SYSMODE_CFG_TYPEC_DISABLE, 0); > + if (ret) > + goto out; > + > + ret = regmap_read(priv->usb31misc, TCA_TCPC, &val); > + if (ret) > + goto out; > + val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK); > + val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31); > + ret = regmap_write(priv->usb31misc, TCA_TCPC, val); > + if (ret) > + goto out; > + > + ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL, > + VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD); > + if (ret) > + goto out; > + > + return 0; > +out: > + dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); > + return ret; > +} > + > +static int hi3670_phy_init(struct phy *phy) > +{ > + struct hi3670_priv *priv = phy_get_drvdata(phy); > + u32 val; > + int ret; > + > + /* assert controller */ > + val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET | > + CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0); > + if (ret) > + goto out; > + > + ret = hi3670_config_phy_clock(priv); > + if (ret) > + goto out; > + > + /* Exit from IDDQ mode */ > + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5, > + CTRL5_USB2_SIDDQ, 0); > + if (ret) > + goto out; > + > + /* Release USB31 PHY out of TestPowerDown mode */ > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50, > + CFG50_USB3_PHY_TEST_POWERDOWN, 0); > + if (ret) > + goto out; > + > + /* Deassert phy */ > + val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); > + if (ret) > + goto out; > + > + usleep_range(100, 120); > + > + /* Tell the PHY power is stable */ > + val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE | > + CFG54_PHY0_PMA_PWR_STABLE; > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, > + val, val); > + if (ret) > + goto out; > + > + ret = hi3670_config_tca(priv); > + if (ret) > + goto out; > + > + /* Enable SSC */ > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C, > + CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN, > + CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN); > + if (ret) > + goto out; > + > + /* Deassert controller */ > + val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET; > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); > + if (ret) > + goto out; > + > + usleep_range(100, 120); > + > + /* Set fake vbus valid signal */ > + val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL; > + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val); > + if (ret) > + goto out; > + > + val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0; > + ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val); > + if (ret) > + goto out; > + > + usleep_range(100, 120); > + > + ret = hi3670_phy_set_params(priv); > + if (ret) > + goto out; > + > + return 0; > +out: > + dev_err(priv->dev, "failed to init phy ret: %d\n", ret); > + return ret; > +} > + > +static int hi3670_phy_exit(struct phy *phy) > +{ > + struct hi3670_priv *priv = phy_get_drvdata(phy); > + u32 mask; > + int ret; > + > + /* Assert phy */ > + mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > + ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0); > + if (ret) > + goto out; > + > + if (hi3670_is_abbclk_seleted(priv)) { > + /* disable usb_tcxo_en */ > + ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, > + USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START); > + } else { > + ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6, > + GT_CLK_USB2PHY_REF); > + if (ret) > + goto out; > + } > + > + return 0; > +out: > + dev_err(priv->dev, "failed to exit phy ret: %d\n", ret); > + return ret; > +} > + > +static struct phy_ops hi3670_phy_ops = { > + .init = hi3670_phy_init, > + .exit = hi3670_phy_exit, > + .owner = THIS_MODULE, > +}; > + > +static int hi3670_phy_probe(struct platform_device *pdev) > +{ > + struct phy_provider *phy_provider; > + struct device *dev = &pdev->dev; > + struct phy *phy; > + struct hi3670_priv *priv; > + > + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + priv->dev = dev; > + priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node, > + "hisilicon,pericrg-syscon"); > + if (IS_ERR(priv->peri_crg)) { > + dev_err(dev, "no hisilicon,pericrg-syscon\n"); > + return PTR_ERR(priv->peri_crg); > + } > + > + priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node, > + "hisilicon,pctrl-syscon"); > + if (IS_ERR(priv->pctrl)) { > + dev_err(dev, "no hisilicon,pctrl-syscon\n"); > + return PTR_ERR(priv->pctrl); > + } > + > + priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node, > + "hisilicon,sctrl-syscon"); > + if (IS_ERR(priv->sctrl)) { > + dev_err(dev, "no hisilicon,sctrl-syscon\n"); > + return PTR_ERR(priv->sctrl); > + } > + > + /* node of hi3670 phy is a sub-node of usb3_otg_bc */ > + priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node); > + if (IS_ERR(priv->usb31misc)) { > + dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n"); > + return PTR_ERR(priv->usb31misc); > + } > + > + if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param", > + &priv->eye_diagram_param)) > + priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM; > + > + if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl", > + &priv->tx_vboost_lvl)) > + priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST; > + > + phy = devm_phy_create(dev, NULL, &hi3670_phy_ops); > + if (IS_ERR(phy)) > + return PTR_ERR(phy); > + > + phy_set_drvdata(phy, priv); > + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + return PTR_ERR_OR_ZERO(phy_provider); > +} > + > +static const struct of_device_id hi3670_phy_of_match[] = { > + { .compatible = "hisilicon,hi3670-usb-phy" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, hi3670_phy_of_match); > + > +static struct platform_driver hi3670_phy_driver = { > + .probe = hi3670_phy_probe, > + .driver = { > + .name = "hi3670-usb-phy", > + .of_match_table = hi3670_phy_of_match, > + } > +}; > +module_platform_driver(hi3670_phy_driver); > + > +MODULE_AUTHOR("Yu Chen "); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver"); > diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig > index b29f5d5df134..0e97b5b9a56a 100644 > --- a/drivers/staging/hikey9xx/Kconfig > +++ b/drivers/staging/hikey9xx/Kconfig > @@ -1,16 +1,5 @@ > # SPDX-License-Identifier: GPL-2.0 > > -# to be placed at drivers/phy > -config PHY_HI3670_USB > - tristate "hi3670 USB PHY support" > - depends on (ARCH_HISI && ARM64) || COMPILE_TEST > - select GENERIC_PHY > - select MFD_SYSCON > - help > - Enable this to support the HISILICON HI3670 USB PHY. > - > - To compile this driver as a module, choose M here. > - > # to be placed at drivers/spmi > config SPMI_HISI3670 > tristate "Hisilicon 3670 SPMI Controller" > diff --git a/drivers/staging/hikey9xx/Makefile b/drivers/staging/hikey9xx/Makefile > index 1924fadac952..9371dcc3d35b 100644 > --- a/drivers/staging/hikey9xx/Makefile > +++ b/drivers/staging/hikey9xx/Makefile > @@ -1,7 +1,5 @@ > # SPDX-License-Identifier: GPL-2.0 > > -obj-$(CONFIG_PHY_HI3670_USB) += phy-hi3670-usb3.o > - > obj-$(CONFIG_SPMI_HISI3670) += hisi-spmi-controller.o > obj-$(CONFIG_MFD_HI6421_SPMI) += hi6421-spmi-pmic.o > obj-$(CONFIG_REGULATOR_HI6421V600) += hi6421v600-regulator.o > diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.c b/drivers/staging/hikey9xx/phy-hi3670-usb3.c > deleted file mode 100644 > index 4fc013911a78..000000000000 > --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.c > +++ /dev/null > @@ -1,671 +0,0 @@ > -// SPDX-License-Identifier: GPL-2.0-only > -/* > - * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform > - * > - * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd. > - * http://www.huawei.com > - * > - * Authors: Yu Chen > - */ > - > -#include > -#include > -#include > -#include > -#include > -#include > -#include > - > -#define SCTRL_SCDEEPSLEEPED (0x0) > -#define USB_CLK_SELECTED BIT(20) > - > -#define PERI_CRG_PEREN0 (0x00) > -#define PERI_CRG_PERDIS0 (0x04) > -#define PERI_CRG_PEREN4 (0x40) > -#define PERI_CRG_PERDIS4 (0x44) > -#define PERI_CRG_PERRSTEN4 (0x90) > -#define PERI_CRG_PERRSTDIS4 (0x94) > -#define PERI_CRG_ISODIS (0x148) > -#define PERI_CRG_PEREN6 (0x410) > -#define PERI_CRG_PERDIS6 (0x414) > - > -#define USB_REFCLK_ISO_EN BIT(25) > - > -#define GT_CLK_USB2PHY_REF BIT(19) > - > -#define PCTRL_PERI_CTRL3 (0x10) > -#define PCTRL_PERI_CTRL3_MSK_START (16) > -#define USB_TCXO_EN BIT(1) > - > -#define PCTRL_PERI_CTRL24 (0x64) > -#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25) > - > -#define USB3OTG_CTRL0 (0x00) > -#define USB3OTG_CTRL3 (0x0C) > -#define USB3OTG_CTRL4 (0x10) > -#define USB3OTG_CTRL5 (0x14) > -#define USB3OTG_CTRL7 (0x1C) > -#define USB_MISC_CFG50 (0x50) > -#define USB_MISC_CFG54 (0x54) > -#define USB_MISC_CFG58 (0x58) > -#define USB_MISC_CFG5C (0x5C) > -#define USB_MISC_CFGA0 (0xA0) > -#define TCA_CLK_RST (0x200) > -#define TCA_INTR_EN (0x204) > -#define TCA_INTR_STS (0x208) > -#define TCA_GCFG (0x210) > -#define TCA_TCPC (0x214) > -#define TCA_SYSMODE_CFG (0x218) > -#define TCA_VBUS_CTRL (0x240) > - > -#define CTRL0_USB3_VBUSVLD BIT(7) > -#define CTRL0_USB3_VBUSVLD_SEL BIT(6) > - > -#define CTRL3_USB2_VBUSVLDEXT0 BIT(6) > -#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5) > - > -#define CTRL5_USB2_SIDDQ BIT(0) > - > -#define CTRL7_USB2_REFCLKSEL_MASK (3 << 3) > -#define CTRL7_USB2_REFCLKSEL_ABB (3 << 3) > -#define CTRL7_USB2_REFCLKSEL_PAD (2 << 3) > - > -#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23) > - > -#define CFG54_USB31PHY_CR_ADDR_MASK (0xFFFF) > -#define CFG54_USB31PHY_CR_ADDR_SHIFT (16) > -#define CFG54_USB3PHY_REF_USE_PAD BIT(12) > -#define CFG54_PHY0_PMA_PWR_STABLE BIT(11) > -#define CFG54_PHY0_PCS_PWR_STABLE BIT(9) > -#define CFG54_USB31PHY_CR_ACK BIT(7) > -#define CFG54_USB31PHY_CR_WR_EN BIT(5) > -#define CFG54_USB31PHY_CR_SEL BIT(4) > -#define CFG54_USB31PHY_CR_RD_EN BIT(3) > -#define CFG54_USB31PHY_CR_CLK BIT(2) > -#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1) > - > -#define CFG58_USB31PHY_CR_DATA_MASK (0xFFFF) > -#define CFG58_USB31PHY_CR_DATA_RD_START (16) > - > -#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1) > - > -#define CFGA0_VAUX_RESET BIT(9) > -#define CFGA0_USB31C_RESET BIT(8) > -#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4) > -#define CFGA0_USB3PHY_RESET BIT(1) > -#define CFGA0_USB2PHY_POR BIT(0) > - > -#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1) > -#define INTR_EN_XA_ACK_EVT_EN BIT(0) > - > -#define CLK_RST_TCA_REF_CLK_EN BIT(1) > -#define CLK_RST_SUSPEND_CLK_EN BIT(0) > - > -#define GCFG_ROLE_HSTDEV BIT(4) > -#define GCFG_OP_MODE (3 << 0) > -#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0) > - > -#define TCPC_VALID BIT(4) > -#define TCPC_LOW_POWER_EN BIT(3) > -#define TCPC_MUX_CONTROL_MASK (3 << 0) > -#define TCPC_MUX_CONTROL_USB31 BIT(0) > - > -#define SYSMODE_CFG_TYPEC_DISABLE BIT(3) > - > -#define VBUS_CTRL_POWERPRESENT_OVERRD (3 << 2) > -#define VBUS_CTRL_VBUSVALID_OVERRD (3 << 0) > - > -#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xFDFEE4) > -#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5) > - > -#define TX_VBOOST_LVL_REG (0xf) > -#define TX_VBOOST_LVL_START (6) > -#define TX_VBOOST_LVL_ENABLE BIT(9) > - > -struct hi3670_priv { > - struct device *dev; > - struct regmap *peri_crg; > - struct regmap *pctrl; > - struct regmap *sctrl; > - struct regmap *usb31misc; > - > - u32 eye_diagram_param; > - u32 tx_vboost_lvl; > - > - u32 peri_crg_offset; > - u32 pctrl_offset; > - u32 usb31misc_offset; > -}; > - > -static int hi3670_phy_cr_clk(struct regmap *usb31misc) > -{ > - int ret; > - > - /* Clock up */ > - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK); > - if (ret) > - return ret; > - > - /* Clock down */ > - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_CLK, 0); > - > - return ret; > -} > - > -static int hi3670_phy_cr_set_sel(struct regmap *usb31misc) > -{ > - return regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL); > -} > - > -static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction) > -{ > - int ret; > - > - if (direction) > - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_WR_EN, > - CFG54_USB31PHY_CR_WR_EN); > - else > - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_RD_EN, > - CFG54_USB31PHY_CR_RD_EN); > - > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_clk(usb31misc); > - if (ret) > - return ret; > - > - ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > - CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0); > - > - return ret; > -} > - > -static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc) > -{ > - u32 reg; > - int retry = 100000; > - int ret; > - > - while (retry-- > 0) { > - ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > - if (ret) > - return ret; > - if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK) > - return 0; > - > - ret = hi3670_phy_cr_clk(usb31misc); > - if (ret) > - return ret; > - } > - > - return -ETIMEDOUT; > -} > - > -static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr) > -{ > - u32 reg; > - int ret; > - > - ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > - if (ret) > - return ret; > - > - reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT); > - reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT); > - ret = regmap_write(usb31misc, USB_MISC_CFG54, reg); > - > - return ret; > -} > - > -static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val) > -{ > - int reg; > - int i; > - int ret; > - > - for (i = 0; i < 100; i++) { > - ret = hi3670_phy_cr_clk(usb31misc); > - if (ret) > - return ret; > - } > - > - ret = hi3670_phy_cr_set_sel(usb31misc); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_set_addr(usb31misc, addr); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_start(usb31misc, 0); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_wait_ack(usb31misc); > - if (ret) > - return ret; > - > - ret = regmap_read(usb31misc, USB_MISC_CFG58, ®); > - if (ret) > - return ret; > - > - *val = (reg >> CFG58_USB31PHY_CR_DATA_RD_START) & > - CFG58_USB31PHY_CR_DATA_MASK; > - > - return 0; > -} > - > -static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val) > -{ > - int i; > - int ret; > - > - for (i = 0; i < 100; i++) { > - ret = hi3670_phy_cr_clk(usb31misc); > - if (ret) > - return ret; > - } > - > - ret = hi3670_phy_cr_set_sel(usb31misc); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_set_addr(usb31misc, addr); > - if (ret) > - return ret; > - > - ret = regmap_write(usb31misc, USB_MISC_CFG58, > - val & CFG58_USB31PHY_CR_DATA_MASK); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_start(usb31misc, 1); > - if (ret) > - return ret; > - > - ret = hi3670_phy_cr_wait_ack(usb31misc); > - > - return ret; > -} > - > -static int hi3670_phy_set_params(struct hi3670_priv *priv) > -{ > - u32 reg; > - int ret; > - int retry = 3; > - > - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL4, > - priv->eye_diagram_param); > - if (ret) { > - dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n"); > - return ret; > - } > - > - while (retry-- > 0) { > - ret = hi3670_phy_cr_read(priv->usb31misc, > - TX_VBOOST_LVL_REG, ®); > - if (!ret) > - break; > - > - if (ret != -ETIMEDOUT) { > - dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n"); > - return ret; > - } > - } > - if (ret) > - return ret; > - > - reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START)); > - ret = hi3670_phy_cr_write(priv->usb31misc, TX_VBOOST_LVL_REG, reg); > - if (ret) > - dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n"); > - > - return ret; > -} > - > -static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv) > -{ > - u32 reg; > - > - if (!priv->sctrl) { > - dev_err(priv->dev, "priv->sctrl is null!\n"); > - return 1; > - } > - > - if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) { > - dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n"); > - return 1; > - } > - > - if ((reg & USB_CLK_SELECTED) == 0) > - return 1; > - > - return 0; > -} > - > -static int hi3670_config_phy_clock(struct hi3670_priv *priv) > -{ > - u32 val, mask; > - int ret; > - > - if (hi3670_is_abbclk_seleted(priv)) { > - /* usb refclk iso disable */ > - ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, > - USB_REFCLK_ISO_EN); > - if (ret) > - goto out; > - > - /* enable usb_tcxo_en */ > - ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, > - USB_TCXO_EN | > - (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START)); > - > - /* select usbphy clk from abb */ > - mask = SC_CLK_USB3PHY_3MUX1_SEL; > - ret = regmap_update_bits(priv->pctrl, > - PCTRL_PERI_CTRL24, mask, 0); > - if (ret) > - goto out; > - > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, > - CFGA0_USB2PHY_REFCLK_SELECT, 0); > - if (ret) > - goto out; > - > - ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); > - if (ret) > - goto out; > - val &= ~CTRL7_USB2_REFCLKSEL_MASK; > - val |= CTRL7_USB2_REFCLKSEL_ABB; > - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); > - if (ret) > - goto out; > - > - return 0; > - } > - > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, > - CFG54_USB3PHY_REF_USE_PAD, > - CFG54_USB3PHY_REF_USE_PAD); > - if (ret) > - goto out; > - > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, > - CFGA0_USB2PHY_REFCLK_SELECT, > - CFGA0_USB2PHY_REFCLK_SELECT); > - if (ret) > - goto out; > - > - ret = regmap_read(priv->usb31misc, USB3OTG_CTRL7, &val); > - if (ret) > - goto out; > - val &= ~CTRL7_USB2_REFCLKSEL_MASK; > - val |= CTRL7_USB2_REFCLKSEL_PAD; > - ret = regmap_write(priv->usb31misc, USB3OTG_CTRL7, val); > - if (ret) > - goto out; > - > - ret = regmap_write(priv->peri_crg, > - PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF); > - if (ret) > - goto out; > - > - return 0; > -out: > - dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); > - return ret; > -} > - > -static int hi3670_config_tca(struct hi3670_priv *priv) > -{ > - u32 val, mask; > - int ret; > - > - ret = regmap_write(priv->usb31misc, TCA_INTR_STS, 0xffff); > - if (ret) > - goto out; > - > - ret = regmap_write(priv->usb31misc, TCA_INTR_EN, > - INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN); > - if (ret) > - goto out; > - > - mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN; > - ret = regmap_update_bits(priv->usb31misc, TCA_CLK_RST, mask, 0); > - if (ret) > - goto out; > - > - ret = regmap_update_bits(priv->usb31misc, TCA_GCFG, > - GCFG_ROLE_HSTDEV | GCFG_OP_MODE, > - GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE); > - if (ret) > - goto out; > - > - ret = regmap_update_bits(priv->usb31misc, TCA_SYSMODE_CFG, > - SYSMODE_CFG_TYPEC_DISABLE, 0); > - if (ret) > - goto out; > - > - ret = regmap_read(priv->usb31misc, TCA_TCPC, &val); > - if (ret) > - goto out; > - val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK); > - val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31); > - ret = regmap_write(priv->usb31misc, TCA_TCPC, val); > - if (ret) > - goto out; > - > - ret = regmap_write(priv->usb31misc, TCA_VBUS_CTRL, > - VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD); > - if (ret) > - goto out; > - > - return 0; > -out: > - dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret); > - return ret; > -} > - > -static int hi3670_phy_init(struct phy *phy) > -{ > - struct hi3670_priv *priv = phy_get_drvdata(phy); > - u32 val; > - int ret; > - > - /* assert controller */ > - val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET | > - CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, 0); > - if (ret) > - goto out; > - > - ret = hi3670_config_phy_clock(priv); > - if (ret) > - goto out; > - > - /* Exit from IDDQ mode */ > - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL5, > - CTRL5_USB2_SIDDQ, 0); > - if (ret) > - goto out; > - > - /* Release USB31 PHY out of TestPowerDown mode */ > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG50, > - CFG50_USB3_PHY_TEST_POWERDOWN, 0); > - if (ret) > - goto out; > - > - /* Deassert phy */ > - val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); > - if (ret) > - goto out; > - > - usleep_range(100, 120); > - > - /* Tell the PHY power is stable */ > - val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE | > - CFG54_PHY0_PMA_PWR_STABLE; > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG54, > - val, val); > - if (ret) > - goto out; > - > - ret = hi3670_config_tca(priv); > - if (ret) > - goto out; > - > - /* Enable SSC */ > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFG5C, > - CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN, > - CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN); > - if (ret) > - goto out; > - > - /* Deassert controller */ > - val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET; > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, val, val); > - if (ret) > - goto out; > - > - usleep_range(100, 120); > - > - /* Set fake vbus valid signal */ > - val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL; > - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL0, val, val); > - if (ret) > - goto out; > - > - val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0; > - ret = regmap_update_bits(priv->usb31misc, USB3OTG_CTRL3, val, val); > - if (ret) > - goto out; > - > - usleep_range(100, 120); > - > - ret = hi3670_phy_set_params(priv); > - if (ret) > - goto out; > - > - return 0; > -out: > - dev_err(priv->dev, "failed to init phy ret: %d\n", ret); > - return ret; > -} > - > -static int hi3670_phy_exit(struct phy *phy) > -{ > - struct hi3670_priv *priv = phy_get_drvdata(phy); > - u32 mask; > - int ret; > - > - /* Assert phy */ > - mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR; > - ret = regmap_update_bits(priv->usb31misc, USB_MISC_CFGA0, mask, 0); > - if (ret) > - goto out; > - > - if (hi3670_is_abbclk_seleted(priv)) { > - /* disable usb_tcxo_en */ > - ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, > - USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START); > - } else { > - ret = regmap_write(priv->peri_crg, PERI_CRG_PERDIS6, > - GT_CLK_USB2PHY_REF); > - if (ret) > - goto out; > - } > - > - return 0; > -out: > - dev_err(priv->dev, "failed to exit phy ret: %d\n", ret); > - return ret; > -} > - > -static struct phy_ops hi3670_phy_ops = { > - .init = hi3670_phy_init, > - .exit = hi3670_phy_exit, > - .owner = THIS_MODULE, > -}; > - > -static int hi3670_phy_probe(struct platform_device *pdev) > -{ > - struct phy_provider *phy_provider; > - struct device *dev = &pdev->dev; > - struct phy *phy; > - struct hi3670_priv *priv; > - > - priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); > - if (!priv) > - return -ENOMEM; > - > - priv->dev = dev; > - priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node, > - "hisilicon,pericrg-syscon"); > - if (IS_ERR(priv->peri_crg)) { > - dev_err(dev, "no hisilicon,pericrg-syscon\n"); > - return PTR_ERR(priv->peri_crg); > - } > - > - priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node, > - "hisilicon,pctrl-syscon"); > - if (IS_ERR(priv->pctrl)) { > - dev_err(dev, "no hisilicon,pctrl-syscon\n"); > - return PTR_ERR(priv->pctrl); > - } > - > - priv->sctrl = syscon_regmap_lookup_by_phandle(dev->of_node, > - "hisilicon,sctrl-syscon"); > - if (IS_ERR(priv->sctrl)) { > - dev_err(dev, "no hisilicon,sctrl-syscon\n"); > - return PTR_ERR(priv->sctrl); > - } > - > - /* node of hi3670 phy is a sub-node of usb3_otg_bc */ > - priv->usb31misc = syscon_node_to_regmap(dev->parent->of_node); > - if (IS_ERR(priv->usb31misc)) { > - dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n"); > - return PTR_ERR(priv->usb31misc); > - } > - > - if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param", > - &priv->eye_diagram_param)) > - priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM; > - > - if (of_property_read_u32(dev->of_node, "hisilicon,tx-vboost-lvl", > - &priv->tx_vboost_lvl)) > - priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST; > - > - phy = devm_phy_create(dev, NULL, &hi3670_phy_ops); > - if (IS_ERR(phy)) > - return PTR_ERR(phy); > - > - phy_set_drvdata(phy, priv); > - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > - return PTR_ERR_OR_ZERO(phy_provider); > -} > - > -static const struct of_device_id hi3670_phy_of_match[] = { > - { .compatible = "hisilicon,hi3670-usb-phy" }, > - { }, > -}; > -MODULE_DEVICE_TABLE(of, hi3670_phy_of_match); > - > -static struct platform_driver hi3670_phy_driver = { > - .probe = hi3670_phy_probe, > - .driver = { > - .name = "hi3670-usb-phy", > - .of_match_table = hi3670_phy_of_match, > - } > -}; > -module_platform_driver(hi3670_phy_driver); > - > -MODULE_AUTHOR("Yu Chen "); > -MODULE_LICENSE("GPL v2"); > -MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver"); > diff --git a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml b/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml > deleted file mode 100644 > index 125a5d6546ae..000000000000 > --- a/drivers/staging/hikey9xx/phy-hi3670-usb3.yaml > +++ /dev/null > @@ -1,72 +0,0 @@ > -# SPDX-License-Identifier: GPL-2.0 > -%YAML 1.2 > ---- > -$id: http://devicetree.org/schemas/phy/hisilicon,hi3670-usb3.yaml# > -$schema: http://devicetree.org/meta-schemas/core.yaml# > - > -title: Hisilicon Kirin970 USB PHY > - > -maintainers: > - - Mauro Carvalho Chehab > -description: |+ > - Bindings for USB3 PHY on HiSilicon Kirin 970. > - > -properties: > - compatible: > - const: hisilicon,hi3670-usb-phy > - > - "#phy-cells": > - const: 0 > - > - hisilicon,pericrg-syscon: > - $ref: '/schemas/types.yaml#/definitions/phandle' > - description: phandle of syscon used to control iso refclk. > - > - hisilicon,pctrl-syscon: > - $ref: '/schemas/types.yaml#/definitions/phandle' > - description: phandle of syscon used to control usb tcxo. > - > - hisilicon,sctrl-syscon: > - $ref: '/schemas/types.yaml#/definitions/phandle' > - description: phandle of syscon used to control phy deep sleep. > - > - hisilicon,eye-diagram-param: > - $ref: /schemas/types.yaml#/definitions/uint32 > - description: Eye diagram for phy. > - > - hisilicon,tx-vboost-lvl: > - $ref: /schemas/types.yaml#/definitions/uint32 > - description: TX level vboost for phy. > - > -required: > - - compatible > - - hisilicon,pericrg-syscon > - - hisilicon,pctrl-syscon > - - hisilicon,sctrl-syscon > - - hisilicon,eye-diagram-param > - - hisilicon,tx-vboost-lvl > - - "#phy-cells" > - > -additionalProperties: false > - > -examples: > - - | > - bus { > - #address-cells = <2>; > - #size-cells = <2>; > - > - usb3_otg_bc: usb3_otg_bc at ff200000 { > - compatible = "syscon", "simple-mfd"; > - reg = <0x0 0xff200000 0x0 0x1000>; > - > - usb_phy { > - compatible = "hisilicon,hi3670-usb-phy"; > - #phy-cells = <0>; > - hisilicon,pericrg-syscon = <&crg_ctrl>; > - hisilicon,pctrl-syscon = <&pctrl>; > - hisilicon,sctrl-syscon = <&sctrl>; > - hisilicon,eye-diagram-param = <0xfdfee4>; > - hisilicon,tx-vboost-lvl = <0x5>; > - }; > - }; > - }; > -- > 2.28.0 > From robh at kernel.org Mon Nov 16 15:31:36 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 16 Nov 2020 09:31:36 -0600 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> References: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201116153136.GA1684546@bogus> On Mon, 16 Nov 2020 13:59:27 +0100, Mauro Carvalho Chehab wrote: > The phy USB3 driver for Hisilicon 970 (hi3670) is ready > for mainstream. Mode it from staging into the main driver's > phy/ directory. > > Signed-off-by: Mauro Carvalho Chehab > --- > .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ > MAINTAINERS | 9 +- > drivers/phy/hisilicon/Kconfig | 10 + > drivers/phy/hisilicon/Makefile | 1 + > drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ > drivers/staging/hikey9xx/Kconfig | 11 - > drivers/staging/hikey9xx/Makefile | 2 - > drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ > drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- > 9 files changed, 762 insertions(+), 757 deletions(-) > create mode 100644 Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml > create mode 100644 drivers/phy/hisilicon/phy-hi3670-usb3.c > delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.c > delete mode 100644 drivers/staging/hikey9xx/phy-hi3670-usb3.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: ./Documentation/devicetree/bindings/phy/phy-hi3670-usb3.yaml: $id: relative path/filename doesn't match actual path or filename expected: http://devicetree.org/schemas/phy/phy-hi3670-usb3.yaml# See https://patchwork.ozlabs.org/patch/1400895 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From robh at kernel.org Mon Nov 16 15:32:02 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 16 Nov 2020 09:32:02 -0600 Subject: [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging In-Reply-To: <7e01d84b31d561fa4df1d42369e4222f4a41a8d3.1605530560.git.mchehab+huawei@kernel.org> References: <7e01d84b31d561fa4df1d42369e4222f4a41a8d3.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201116153202.GA1685169@bogus> On Mon, 16 Nov 2020 13:59:28 +0100, Mauro Carvalho Chehab wrote: > The Hisilicon 6421v600 SPMI driver is ready for mainstream. > > So, move it from staging. > > Signed-off-by: Mauro Carvalho Chehab > --- > .../spmi/hisilicon,hisi-spmi-controller.yaml | 62 +++ > MAINTAINERS | 7 + > drivers/spmi/Kconfig | 9 + > drivers/spmi/Makefile | 1 + > drivers/spmi/hisi-spmi-controller.c | 358 ++++++++++++++++++ > drivers/staging/hikey9xx/Kconfig | 11 - > drivers/staging/hikey9xx/Makefile | 1 - > .../staging/hikey9xx/hisi-spmi-controller.c | 358 ------------------ > .../hisilicon,hisi-spmi-controller.yaml | 62 --- > 9 files changed, 437 insertions(+), 432 deletions(-) > create mode 100644 Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml > create mode 100644 drivers/spmi/hisi-spmi-controller.c > delete mode 100644 drivers/staging/hikey9xx/hisi-spmi-controller.c > delete mode 100644 drivers/staging/hikey9xx/hisilicon,hisi-spmi-controller.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: ./Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml:34:2: [warning] wrong indentation: expected 2 but found 1 (indentation) dtschema/dtc warnings/errors: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml: 'additionalProperties' is a required property /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml: ignoring, error in schema: warning: no schema found in file: ./Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.yaml Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dts:29.20-31.15: Warning (unit_address_vs_reg): /example-0/bus/spmi at fff24000/pmic at 0: node has a unit name, but no reg or ranges property /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/hisilicon,hisi-spmi-controller.example.dt.yaml: spmi at fff24000: pmic at 0: 'reg' is a required property From schema: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/spmi/spmi.yaml See https://patchwork.ozlabs.org/patch/1400897 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From robh at kernel.org Mon Nov 16 15:32:37 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 16 Nov 2020 09:32:37 -0600 Subject: [PATCH 3/8] mfd: hi6421-spmi-pmic: move driver from staging In-Reply-To: <504469db0d6659fdaed550a89822be6e7b8dc85e.1605530560.git.mchehab+huawei@kernel.org> References: <504469db0d6659fdaed550a89822be6e7b8dc85e.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201116153237.GA1685828@bogus> On Mon, 16 Nov 2020 13:59:29 +0100, Mauro Carvalho Chehab wrote: > This driver is ready for mainstream. So, move it out of staging. > > Signed-off-by: Mauro Carvalho Chehab > --- > .../mfd/hisilicon,hi6421-spmi-pmic.yaml | 159 ++++++++ > MAINTAINERS | 7 + > drivers/mfd/Kconfig | 15 + > drivers/mfd/Makefile | 1 + > drivers/mfd/hi6421-spmi-pmic.c | 342 ++++++++++++++++++ > drivers/staging/hikey9xx/Kconfig | 16 - > drivers/staging/hikey9xx/Makefile | 1 - > drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 342 ------------------ > .../hikey9xx/hisilicon,hi6421-spmi-pmic.yaml | 159 -------- > 9 files changed, 524 insertions(+), 518 deletions(-) > create mode 100644 Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml > create mode 100644 drivers/mfd/hi6421-spmi-pmic.c > delete mode 100644 drivers/staging/hikey9xx/hi6421-spmi-pmic.c > delete mode 100644 drivers/staging/hikey9xx/hisilicon,hi6421-spmi-pmic.yaml > My bot found errors running 'make dt_binding_check' on your patch: yamllint warnings/errors: dtschema/dtc warnings/errors: /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: 'additionalProperties' is a required property /builds/robherring/linux-dt-review/Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml: ignoring, error in schema: warning: no schema found in file: ./Documentation/devicetree/bindings/mfd/hisilicon,hi6421-spmi-pmic.yaml See https://patchwork.ozlabs.org/patch/1400898 The base for the patch is generally the last rc1. Any dependencies should be noted. If you already ran 'make dt_binding_check' and didn't see the above error(s), then make sure 'yamllint' is installed and dt-schema is up to date: pip3 install dtschema --upgrade Please check and re-submit. From broonie at kernel.org Mon Nov 16 18:38:33 2020 From: broonie at kernel.org (Mark Brown) Date: Mon, 16 Nov 2020 18:38:33 +0000 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> References: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201116183833.GC4739@sirena.org.uk> On Mon, Nov 16, 2020 at 01:59:30PM +0100, Mauro Carvalho Chehab wrote: > This driver is ready for mainstream. Move it out of staging. There's quite a few issues here, to be honest I'm disappointed some of them weren't caught during staging review, this needs fairly substantial work and there's signs that this also applies to at least the MFD portion. This also appears to be missing a DT binding document, binding documentation is required for anything with DT support. > +config REGULATOR_HI6421V600 > + tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" > + depends on MFD_HI6421_SPMI && OF > + depends on REGULATOR This is inside an if REGULATOR block, as with all the other regulator drivers it doesn't need a dependency on REGULATOR. > --- /dev/null > +++ b/drivers/regulator/hi6421v600-regulator.c > @@ -0,0 +1,478 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Device driver for regulators in Hisi IC Please make the entire comment a C++ one so things look more intentional. > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include Are we sure about *all* these includes? > +#define rdev_dbg(rdev, fmt, arg...) \ > + pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg) If it is useful to copy this then put it in a header rather than cut'n'pasting it. I'm not sure I see a pressing need for most of the trace here, it looks to be duplicating a lot of things the core does for you. > +static DEFINE_MUTEX(enable_mutex); Drivers shouldn't be declaring global variables, if this is required it should be allocated in driver data. > +/* > + * helper function to ensure when it returns it is at least 'delay_us' > + * microseconds after 'since'. > + */ > + > +static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev) The helper function appears to have been removed? > +{ > + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); > + struct hi6421_spmi_pmic *pmic = sreg->pmic; > + u32 reg_val; > + > + reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); > + > + rdev_dbg(rdev, > + "enable_reg=0x%x, val= 0x%x, enable_state=%d\n", > + rdev->desc->enable_reg, > + reg_val, (reg_val & rdev->desc->enable_mask)); > + > + return ((reg_val & rdev->desc->enable_mask) != 0); > +} It looks like it would be less code overall to just implement a regmap for the MFD, even if it were only used in this driver - almost everything in here is just a carbon copy of standard helpers that the core provides for regmap devices. Doing it in the MFD would be more idiomatic for everything though. > +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) > +{ > + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); > + struct hi6421_spmi_pmic *pmic = sreg->pmic; > + > + /* cannot enable more than one regulator at one time */ > + mutex_lock(&enable_mutex); > + usleep_range(HISI_REGS_ENA_PROTECT_TIME, > + HISI_REGS_ENA_PROTECT_TIME + 1000); > + > + /* set enable register */ > + rdev_dbg(rdev, > + "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n", > + rdev->desc->off_on_delay, rdev->desc->enable_reg, > + rdev->desc->enable_mask); > + > + hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, > + rdev->desc->enable_mask, > + rdev->desc->enable_mask); This is the one operation which is doing anything unusual and which I'd expect to be open coded in the driver - obviously this is a pretty simplistic implementation but it will work though as indicated above it shouldn't be using a global, the mutex should be in driver data. I guess you could use the mutex to protect a timestamp and use that to figure out if a delay is actually needed? > +static int hi6421_spmi_dt_parse(struct platform_device *pdev, > + struct hi6421v600_regulator *sreg, > + struct regulator_desc *rdesc) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + unsigned int *v_table; > + int ret; > + > + ret = of_property_read_u32(np, "reg", &rdesc->enable_reg); > + if (ret) { > + dev_err(dev, "missing reg property\n"); > + return ret; > + } > + > + ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg); There is no way this stuff should be being parsed out of DT, we should know the register map for the device and what regulators it has based purely off knowing what device we have. Baking the register map into the ABI is bad practice, it prevents us from improving our support for the hardware without going and updating people's DTs. > + /* > + * Not all regulators work on idle mode > + */ > + ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask); > + if (ret) { > + dev_dbg(dev, "LDO doesn't support economy mode.\n"); > + sreg->eco_mode_mask = 0; > + sreg->eco_uA = 0; > + } else { > + ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA); There's no conditional code to not register the mode operations if the mode information is not available (and again this should be done based on knowing the properties of the device, this is unlikely to be system dependent). > +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev, > + struct device_node *np, > + struct hi6421_spmi_pmic *pmic) > +{ This probe code looks very different to other regulator drivers, this alone should have been a warning that the driver needs some substantial refactoring here. As indicated information about what regulators are present on devices and their properties should be in the driver not the DT, the driver should just be able to register them unconditionally and use of_match and regulators_node to allow the core to find any constraints that are provided by the platform. > + constraint->valid_modes_mask = REGULATOR_MODE_NORMAL; > + if (sreg->eco_mode_mask) { > + constraint->valid_modes_mask |= REGULATOR_MODE_IDLE; > + constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE; > + } This is absolutely not OK, a regulator driver should *not* be modifying the constraints that the machine has set. If it is safe to change modes on a platform and the system integrator wants to do that then they will set the constraints appropriately, there is no way the regulator driver can tell what is appropriate on a given system. The fact that the driver is including machine.h at all ought to have been an indicator that there's an abstraction problem here. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From robh at kernel.org Mon Nov 16 19:16:55 2020 From: robh at kernel.org (Rob Herring) Date: Mon, 16 Nov 2020 13:16:55 -0600 Subject: [PATCH 2/7] dt: bindings: add mt7621-pll device tree binding documentation In-Reply-To: <20201111163013.29412-3-sergio.paracuellos@gmail.com> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> <20201111163013.29412-3-sergio.paracuellos@gmail.com> Message-ID: <20201116191655.GA1981921@bogus> On Wed, 11 Nov 2020 17:30:08 +0100, Sergio Paracuellos wrote: > Adds device tree binding documentation for PLL controller in > the MT7621 SOC. > > Signed-off-by: Sergio Paracuellos > --- > .../bindings/clock/mediatek,mt7621-pll.yaml | 51 +++++++++++++++++++ > 1 file changed, 51 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml > Reviewed-by: Rob Herring From perselis.e at gmail.com Mon Nov 16 20:43:23 2020 From: perselis.e at gmail.com (Emmanouil Perselis) Date: Mon, 16 Nov 2020 21:43:23 +0100 Subject: [PATCH] Fix warning for static const char * array in audio_manager_module.c In-Reply-To: <66314332-e66d-9b34-52f9-ae005df2be15@ieee.org> References: <66314332-e66d-9b34-52f9-ae005df2be15@ieee.org> Message-ID: <20201116204322.2122-1-perselis.e@gmail.com> On 11/15/20 9:17 AM, Greg Kroah-Hartman wrote: > On Sun, Nov 15, 2020 at 03:53:16PM +0100, Emmanouil Perselis wrote: >> This patch fixes the warning "static const char * array should >> probably be static const char * const" in >> drivers/staging/greybus/audio_manager_module.c >> I think Greg's patch bot is telling you that you need >> to carbon-copy the mailing list on your patch submission, >> not just address it to the maintainers. Added addresses to carbon copy. >> -Alex >> >> Signed-off-by: Emmanouil Perselis >> --- >> drivers/staging/greybus/audio_manager_module.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/drivers/staging/greybus/audio_manager_module.c b/drivers/staging/greybus/audio_manager_module.c >> index 2bfd804183c4..6ef7381f4e85 100644 >> --- a/drivers/staging/greybus/audio_manager_module.c >> +++ b/drivers/staging/greybus/audio_manager_module.c >> @@ -158,7 +158,7 @@ static void send_add_uevent(struct gb_audio_manager_module *module) >> char ip_devices_string[64]; >> char op_devices_string[64]; >> >> - char *envp[] = { >> + static const char * const envp[] = { >> name_string, >> vid_string, >> pid_string, >> -- >> 2.20.1 >> > > Hi, > > This is the friendly patch-bot of Greg Kroah-Hartman. You have sent him > a patch that has triggered this response. He used to manually respond > to these common problems, but in order to save his sanity (he kept > writing the same thing over and over, yet to different people), I was > created. Hopefully you will not take offence and will fix the problem > in your patch and resubmit it so that it can be accepted into the Linux > kernel tree. > > You are receiving this message because of the following common error(s) > as indicated below: > > - Your patch was sent privately to Greg. Kernel development is done in > public, please always cc: a public mailing list with a patch > submission. Using the tool, scripts/get_maintainer.pl on the patch > will tell you what mailing list to cc. > > - You did not specify a description of why the patch is needed, or > possibly, any description at all, in the email body. Please read the > section entitled "The canonical patch format" in the kernel file, > Documentation/SubmittingPatches for what is needed in order to > properly describe the change. > > - You did not write a descriptive Subject: for the patch, allowing Greg, > and everyone else, to know what this patch is all about. Please read > the section entitled "The canonical patch format" in the kernel file, > Documentation/SubmittingPatches for what a proper Subject: line should > look like. > > If you wish to discuss this problem further, or you have questions about > how to resolve this issue, please feel free to respond to this email and > Greg will reply once he has dug out from the pending patches received > from other developers. > > thanks, > > greg k-h's patch email bot > Signed-off-by: Emmanouil Perselis --- drivers/staging/greybus/audio_manager_module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/greybus/audio_manager_module.c b/drivers/staging/greybus/audio_manager_module.c index 2bfd804183c4..6ef7381f4e85 100644 --- a/drivers/staging/greybus/audio_manager_module.c +++ b/drivers/staging/greybus/audio_manager_module.c @@ -158,7 +158,7 @@ static void send_add_uevent(struct gb_audio_manager_module *module) char ip_devices_string[64]; char op_devices_string[64]; - char *envp[] = { + static const char * const envp[] = { name_string, vid_string, pid_string, -- 2.20.1 From lkp at intel.com Mon Nov 16 22:15:50 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 17 Nov 2020 06:15:50 +0800 Subject: [PATCH] Fix warning for static const char * array in audio_manager_module.c In-Reply-To: <20201116204322.2122-1-perselis.e@gmail.com> References: <20201116204322.2122-1-perselis.e@gmail.com> Message-ID: <202011170652.lGBxt5uh-lkp@intel.com> Hi Emmanouil, Thank you for the patch! Yet something to improve: [auto build test ERROR on staging/staging-testing] [also build test ERROR on v5.10-rc4 next-20201116] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Emmanouil-Perselis/Fix-warning-for-static-const-char-array-in-audio_manager_module-c/20201117-044852 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 0d79a48440f559ac939d1be2089757c5e4ab16c7 config: microblaze-randconfig-r011-20201116 (attached as .config) compiler: microblaze-linux-gcc (GCC) 9.3.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/69022592162daaee87b29588cd562da4439f0517 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Emmanouil-Perselis/Fix-warning-for-static-const-char-array-in-audio_manager_module-c/20201117-044852 git checkout 69022592162daaee87b29588cd562da4439f0517 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross ARCH=microblaze If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All errors (new ones prefixed by >>): drivers/staging/greybus/audio_manager_module.c: In function 'send_add_uevent': >> drivers/staging/greybus/audio_manager_module.c:162:3: error: initializer element is not constant 162 | name_string, | ^~~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:162:3: note: (near initialization for 'envp[0]') drivers/staging/greybus/audio_manager_module.c:163:3: error: initializer element is not constant 163 | vid_string, | ^~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:163:3: note: (near initialization for 'envp[1]') drivers/staging/greybus/audio_manager_module.c:164:3: error: initializer element is not constant 164 | pid_string, | ^~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:164:3: note: (near initialization for 'envp[2]') drivers/staging/greybus/audio_manager_module.c:165:3: error: initializer element is not constant 165 | intf_id_string, | ^~~~~~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:165:3: note: (near initialization for 'envp[3]') drivers/staging/greybus/audio_manager_module.c:166:3: error: initializer element is not constant 166 | ip_devices_string, | ^~~~~~~~~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:166:3: note: (near initialization for 'envp[4]') drivers/staging/greybus/audio_manager_module.c:167:3: error: initializer element is not constant 167 | op_devices_string, | ^~~~~~~~~~~~~~~~~ drivers/staging/greybus/audio_manager_module.c:167:3: note: (near initialization for 'envp[5]') >> drivers/staging/greybus/audio_manager_module.c:180:46: error: passing argument 3 of 'kobject_uevent_env' from incompatible pointer type [-Werror=incompatible-pointer-types] 180 | kobject_uevent_env(&module->kobj, KOBJ_ADD, envp); | ^~~~ | | | const char * const* In file included from drivers/staging/greybus/audio_manager.h:11, from drivers/staging/greybus/audio_manager_module.c:10: include/linux/kobject.h:241:10: note: expected 'char **' but argument is of type 'const char * const*' 241 | char *envp[]); | ~~~~~~^~~~~~ cc1: some warnings being treated as errors vim +162 drivers/staging/greybus/audio_manager_module.c 8db00736d365b75 Svetlin Ankov 2016-01-13 151 8db00736d365b75 Svetlin Ankov 2016-01-13 152 static void send_add_uevent(struct gb_audio_manager_module *module) 8db00736d365b75 Svetlin Ankov 2016-01-13 153 { 8db00736d365b75 Svetlin Ankov 2016-01-13 154 char name_string[128]; 8db00736d365b75 Svetlin Ankov 2016-01-13 155 char vid_string[64]; 8db00736d365b75 Svetlin Ankov 2016-01-13 156 char pid_string[64]; d0af1bd5f6f4497 Pankaj Bharadiya 2016-10-16 157 char intf_id_string[64]; a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 158 char ip_devices_string[64]; a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 159 char op_devices_string[64]; 8db00736d365b75 Svetlin Ankov 2016-01-13 160 69022592162daae Emmanouil Perselis 2020-11-16 161 static const char * const envp[] = { 8db00736d365b75 Svetlin Ankov 2016-01-13 @162 name_string, 8db00736d365b75 Svetlin Ankov 2016-01-13 163 vid_string, 8db00736d365b75 Svetlin Ankov 2016-01-13 164 pid_string, d0af1bd5f6f4497 Pankaj Bharadiya 2016-10-16 @165 intf_id_string, a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 166 ip_devices_string, a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 167 op_devices_string, 8db00736d365b75 Svetlin Ankov 2016-01-13 168 NULL 8db00736d365b75 Svetlin Ankov 2016-01-13 169 }; 8db00736d365b75 Svetlin Ankov 2016-01-13 170 8db00736d365b75 Svetlin Ankov 2016-01-13 171 snprintf(name_string, 128, "NAME=%s", module->desc.name); 8db00736d365b75 Svetlin Ankov 2016-01-13 172 snprintf(vid_string, 64, "VID=%d", module->desc.vid); 8db00736d365b75 Svetlin Ankov 2016-01-13 173 snprintf(pid_string, 64, "PID=%d", module->desc.pid); d0af1bd5f6f4497 Pankaj Bharadiya 2016-10-16 174 snprintf(intf_id_string, 64, "INTF_ID=%d", module->desc.intf_id); a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 175 snprintf(ip_devices_string, 64, "I/P DEVICES=0x%X", a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 176 module->desc.ip_devices); a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 177 snprintf(op_devices_string, 64, "O/P DEVICES=0x%X", a9234bfd6cec442 Vaibhav Agarwal 2016-03-30 178 module->desc.op_devices); 8db00736d365b75 Svetlin Ankov 2016-01-13 179 8db00736d365b75 Svetlin Ankov 2016-01-13 @180 kobject_uevent_env(&module->kobj, KOBJ_ADD, envp); 8db00736d365b75 Svetlin Ankov 2016-01-13 181 } 8db00736d365b75 Svetlin Ankov 2016-01-13 182 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org -------------- next part -------------- A non-text attachment was scrubbed... Name: .config.gz Type: application/gzip Size: 29150 bytes Desc: not available URL: From nami at 4sasa.xyz Mon Nov 16 22:20:36 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Tue, 17 Nov 2020 06:20:36 +0800 Subject: Greetings Dear Beloved: Message-ID: <20201116222356.CC06385FC0@whitealder.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Melvida Bullock Email:?melvbullockzone123 at gmail.com From nami at 4sasa.xyz Mon Nov 16 22:13:51 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Tue, 17 Nov 2020 06:13:51 +0800 Subject: Greetings Dear Beloved: Message-ID: <20201116222357.3972C85F53@whitealder.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Melvida Bullock Email:?melvbullockzone123 at gmail.com From nami at 4sasa.xyz Mon Nov 16 22:13:51 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Tue, 17 Nov 2020 06:13:51 +0800 Subject: Greetings Dear Beloved: Message-ID: <20201116222357.E68A685F53@whitealder.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Melvida Bullock Email:?melvbullockzone123 at gmail.com From yangyingliang at huawei.com Tue Nov 17 02:50:41 2020 From: yangyingliang at huawei.com (Yang Yingliang) Date: Tue, 17 Nov 2020 10:50:41 +0800 Subject: [PATCH] [media] omap4iss: return error code when omap4iss_get() failed Message-ID: <20201117025041.3424574-1-yangyingliang@huawei.com> If omap4iss_get() failed, it need return error code in iss_probe(). Fixes: 59f0ad807681 ("[media] v4l: omap4iss: Add support for OMAP4...") Reported-by: Hulk Robot Signed-off-by: Yang Yingliang --- drivers/staging/media/omap4iss/iss.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c index e06ea7ea1e50..3dac35f68238 100644 --- a/drivers/staging/media/omap4iss/iss.c +++ b/drivers/staging/media/omap4iss/iss.c @@ -1236,8 +1236,10 @@ static int iss_probe(struct platform_device *pdev) if (ret < 0) goto error; - if (!omap4iss_get(iss)) + if (!omap4iss_get(iss)) { + ret = -EINVAL; goto error; + } ret = iss_reset(iss); if (ret < 0) -- 2.25.1 From sulmbello6745 at gmail.com Tue Nov 17 03:08:58 2020 From: sulmbello6745 at gmail.com (Mr Suleman Bello) Date: Tue, 17 Nov 2020 03:08:58 +0000 Subject: CAN I TRUST YOU? Message-ID: Dear Friend, Please I want you to read this letter very carefully and I must apologize for berging this message into your mailbox without any formal introduction due to the urgency and confidentiality of this issue and I know that this message will come to you as a surprise. Please, I urge you to handle this message as a top secret and I will not like you to joke with it. I am Mr.Suleman Bello, a staff in Bank of Burkina faso (Ouagadougou) As a branch internal auditor of the bank, I discovered an existing dormant account for years without any banking activity going on in it; neither deposits nor withdrawals from this account for this long period. And according to the rules guiding our bank, any unserviceable account for more than (7) seven years will be delisted, and the funds, no matter the amount, will be transferred to the national treasury as an unclaimed fund. I hope you know the meaning of unclaimed funds; an abandoned fund you can?t locate the owner, probably because the owner is dead by sickness, accident, plane crash, natural disaster or murdered without leaving information about the funds to any relative or friend. Or funds looted and abandoned by politicians for the fear of being prosecuted by their government. That's why you have many unclaimed funds littered in different banks everywhere. And It is only staff like in my position as an internal auditor of a bank that often come across such accounts and their details. I hope that you will not expose or betray this trust and confidence that I am about to establish with you for the mutual benefit of you and I. Please, I need us to work together in order to move the funds out immediately to your possession so that we can share it. I will assist you to come up with a beneficiary claim to enable the transferring of the said sum of $10.5 million United States Dollar into your account within 7 banking days. Once it is done, I will resign from my work and use my share for better and lucrative businesses, and remarry since I am divorced, and to continue my life happily in another beautiful and cozy foreign country of my choice, with my new family. As an insider in the bank that you can trust, I can leak-out or secretly reveal to you every information and document about the account including the account statement to enable us facilitate it. The truth is that this account and funds in it have been dormant for years in our Bank, and the request for a foreigner to be involved in this deal becomes necessary because our late customer was a foreigner and a burkinabe cannot stand as Next of Kin to a foreigner. Therefore, because of the nature of this transaction, I want you to stand as the Next of kin so that our bank will accord you the recognition and have the fund transferred to your account. And I promised that I will be guiding you until the end to avoid any mistake. Upon your response, I shall then provide you with further information, including verifiable documents linked to the account and more details that will help you understand the transaction. I am expecting your urgent response to enable me inform you how this deal will be executed. Please I would like you to keep this transaction confidential and as a top secret or delete if you are not interested. With many thanks, Suleman Bello. From dingxiang at cmss.chinamobile.com Tue Nov 17 02:59:33 2020 From: dingxiang at cmss.chinamobile.com (Ding Xiang) Date: Tue, 17 Nov 2020 10:59:33 +0800 Subject: [PATCH] staging: fieldbus: use kobj_to_dev() to get device Message-ID: <20201117025933.668938-1-dingxiang@cmss.chinamobile.com> Use kobj_to_dev() instead of container_of() Signed-off-by: Ding Xiang --- drivers/staging/fieldbus/dev_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c index 1ba0234cc60d..5aab734606ea 100644 --- a/drivers/staging/fieldbus/dev_core.c +++ b/drivers/staging/fieldbus/dev_core.c @@ -134,7 +134,7 @@ static struct attribute *fieldbus_attrs[] = { static umode_t fieldbus_is_visible(struct kobject *kobj, struct attribute *attr, int n) { - struct device *dev = container_of(kobj, struct device, kobj); + struct device *dev = kobj_to_dev(kobj); struct fieldbus_dev *fb = dev_get_drvdata(dev); umode_t mode = attr->mode; -- 2.28.0 From lkp at intel.com Tue Nov 17 03:25:11 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 17 Nov 2020 11:25:11 +0800 Subject: [PATCH] Fix warning for static const char * array in audio_manager_module.c In-Reply-To: <20201116204322.2122-1-perselis.e@gmail.com> References: <20201116204322.2122-1-perselis.e@gmail.com> Message-ID: <202011171133.KUdbQWwf-lkp@intel.com> Hi Emmanouil, Thank you for the patch! Yet something to improve: [auto build test ERROR on staging/staging-testing] [also build test ERROR on v5.10-rc4 next-20201116] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Emmanouil-Perselis/Fix-warning-for-static-const-char-array-in-audio_manager_module-c/20201117-044852 base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git 0d79a48440f559ac939d1be2089757c5e4ab16c7 config: x86_64-randconfig-a006-20201115 (attached as .config) compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project ace9653c11c6308401dcda2e8b26bf97e6e66e30) reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # install x86_64 cross compiling tool for clang build # apt-get install binutils-x86-64-linux-gnu # https://github.com/0day-ci/linux/commit/69022592162daaee87b29588cd562da4439f0517 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Emmanouil-Perselis/Fix-warning-for-static-const-char-array-in-audio_manager_module-c/20201117-044852 git checkout 69022592162daaee87b29588cd562da4439f0517 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot All errors (new ones prefixed by >>): >> drivers/staging/greybus/audio_manager_module.c:162:3: error: initializer element is not a compile-time constant name_string, ^~~~~~~~~~~ >> drivers/staging/greybus/audio_manager_module.c:180:46: error: passing 'const char *const [7]' to parameter of type 'char **' discards qualifiers in nested pointer types [-Werror,-Wincompatible-pointer-types-discards-qualifiers] kobject_uevent_env(&module->kobj, KOBJ_ADD, envp); ^~~~ include/linux/kobject.h:241:10: note: passing argument to parameter 'envp' here char *envp[]); ^ 2 errors generated. vim +162 drivers/staging/greybus/audio_manager_module.c 8db00736d365b7 Svetlin Ankov 2016-01-13 151 8db00736d365b7 Svetlin Ankov 2016-01-13 152 static void send_add_uevent(struct gb_audio_manager_module *module) 8db00736d365b7 Svetlin Ankov 2016-01-13 153 { 8db00736d365b7 Svetlin Ankov 2016-01-13 154 char name_string[128]; 8db00736d365b7 Svetlin Ankov 2016-01-13 155 char vid_string[64]; 8db00736d365b7 Svetlin Ankov 2016-01-13 156 char pid_string[64]; d0af1bd5f6f449 Pankaj Bharadiya 2016-10-16 157 char intf_id_string[64]; a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 158 char ip_devices_string[64]; a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 159 char op_devices_string[64]; 8db00736d365b7 Svetlin Ankov 2016-01-13 160 69022592162daa Emmanouil Perselis 2020-11-16 161 static const char * const envp[] = { 8db00736d365b7 Svetlin Ankov 2016-01-13 @162 name_string, 8db00736d365b7 Svetlin Ankov 2016-01-13 163 vid_string, 8db00736d365b7 Svetlin Ankov 2016-01-13 164 pid_string, d0af1bd5f6f449 Pankaj Bharadiya 2016-10-16 165 intf_id_string, a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 166 ip_devices_string, a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 167 op_devices_string, 8db00736d365b7 Svetlin Ankov 2016-01-13 168 NULL 8db00736d365b7 Svetlin Ankov 2016-01-13 169 }; 8db00736d365b7 Svetlin Ankov 2016-01-13 170 8db00736d365b7 Svetlin Ankov 2016-01-13 171 snprintf(name_string, 128, "NAME=%s", module->desc.name); 8db00736d365b7 Svetlin Ankov 2016-01-13 172 snprintf(vid_string, 64, "VID=%d", module->desc.vid); 8db00736d365b7 Svetlin Ankov 2016-01-13 173 snprintf(pid_string, 64, "PID=%d", module->desc.pid); d0af1bd5f6f449 Pankaj Bharadiya 2016-10-16 174 snprintf(intf_id_string, 64, "INTF_ID=%d", module->desc.intf_id); a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 175 snprintf(ip_devices_string, 64, "I/P DEVICES=0x%X", a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 176 module->desc.ip_devices); a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 177 snprintf(op_devices_string, 64, "O/P DEVICES=0x%X", a9234bfd6cec44 Vaibhav Agarwal 2016-03-30 178 module->desc.op_devices); 8db00736d365b7 Svetlin Ankov 2016-01-13 179 8db00736d365b7 Svetlin Ankov 2016-01-13 @180 kobject_uevent_env(&module->kobj, KOBJ_ADD, envp); 8db00736d365b7 Svetlin Ankov 2016-01-13 181 } 8db00736d365b7 Svetlin Ankov 2016-01-13 182 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org -------------- next part -------------- A non-text attachment was scrubbed... Name: .config.gz Type: application/gzip Size: 37091 bytes Desc: not available URL: From samuel at sholland.org Tue Nov 17 04:36:12 2020 From: samuel at sholland.org (Samuel Holland) Date: Mon, 16 Nov 2020 22:36:12 -0600 Subject: [RFC 2/3] ARM: sunxi: do not select COMMON_CLK to fix builds In-Reply-To: <20201115170950.304460-3-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-3-krzk@kernel.org> Message-ID: On 11/15/20 11:09 AM, Krzysztof Kozlowski wrote: > COMMON_CLK is a user-selectable option with its own dependencies. The > most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers > should not select COMMON_CLK because they will create a dependency cycle > and build failures. For example on MIPS a configuration with COMMON_CLK > (selected by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (selected by > SOC_RT305X) is possible: Ah, that makes sense. > > WARNING: unmet direct dependencies detected for COMMON_CLK > Depends on [n]: !HAVE_LEGACY_CLK [=y] > Selected by [y]: > - SND_SUN8I_CODEC [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && > (ARCH_SUNXI || COMPILE_TEST [=y]) && OF [=y] && (MACH_SUN8I || ARM64 && ARCH_SUNXI || COMPILE_TEST [=y]) > > /usr/bin/mips-linux-gnu-ld: drivers/clk/clk.o: in function `clk_set_rate': > (.text+0xaeb4): multiple definition of `clk_set_rate'; arch/mips/ralink/clk.o:(.text+0x88): first defined here > > Signed-off-by: Krzysztof Kozlowski > --- > arch/arm/mach-sunxi/Kconfig | 1 + > sound/soc/sunxi/Kconfig | 2 +- > 2 files changed, 2 insertions(+), 1 deletion(-) > > diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig > index eeadb1a4dcfe..4d9f9b6d329d 100644 > --- a/arch/arm/mach-sunxi/Kconfig > +++ b/arch/arm/mach-sunxi/Kconfig > @@ -4,6 +4,7 @@ menuconfig ARCH_SUNXI > depends on ARCH_MULTI_V5 || ARCH_MULTI_V7 > select ARCH_HAS_RESET_CONTROLLER > select CLKSRC_MMIO > + select COMMON_CLK This is not necessary, since ARCH_SUNXI depends (through ARCH_MULTI_V{5,7}) on ARCH_MULTIPLATFORM, which selects COMMON_CLK already. > select GENERIC_IRQ_CHIP > select GPIOLIB > select PINCTRL > diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig > index 69b9d8515335..ddcaaa98d3cb 100644 > --- a/sound/soc/sunxi/Kconfig > +++ b/sound/soc/sunxi/Kconfig > @@ -14,7 +14,7 @@ config SND_SUN8I_CODEC > tristate "Allwinner SUN8I audio codec" > depends on OF > depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST > - select COMMON_CLK > + depends on COMMON_CLK > select REGMAP_MMIO > help > This option enables the digital part of the internal audio codec for > For this file: Reviewed-by: Samuel Holland Thanks, Samuel From sergio.paracuellos at gmail.com Tue Nov 17 05:38:37 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Tue, 17 Nov 2020 06:38:37 +0100 Subject: [PATCH 2/7] dt: bindings: add mt7621-pll device tree binding documentation In-Reply-To: <20201116191655.GA1981921@bogus> References: <20201111163013.29412-1-sergio.paracuellos@gmail.com> <20201111163013.29412-3-sergio.paracuellos@gmail.com> <20201116191655.GA1981921@bogus> Message-ID: Hi Rob, On Mon, Nov 16, 2020 at 8:16 PM Rob Herring wrote: > > On Wed, 11 Nov 2020 17:30:08 +0100, Sergio Paracuellos wrote: > > Adds device tree binding documentation for PLL controller in > > the MT7621 SOC. > > > > Signed-off-by: Sergio Paracuellos > > --- > > .../bindings/clock/mediatek,mt7621-pll.yaml | 51 +++++++++++++++++++ > > 1 file changed, 51 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-pll.yaml > > > > Reviewed-by: Rob Herring Thanks for the review. In that series there were two clock bindings relating the pll and gates, There were finally joined in only one binding and driver. This is done in the v3 of this series sent on friday. Thanks for your time in looking also into this new version, Best regards, Sergio Paracuellos From gregkh at linuxfoundation.org Tue Nov 17 06:01:10 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Tue, 17 Nov 2020 07:01:10 +0100 Subject: [PATCH] Fix warning for static const char * array in audio_manager_module.c In-Reply-To: <20201116204322.2122-1-perselis.e@gmail.com> References: <66314332-e66d-9b34-52f9-ae005df2be15@ieee.org> <20201116204322.2122-1-perselis.e@gmail.com> Message-ID: On Mon, Nov 16, 2020 at 09:43:23PM +0100, Emmanouil Perselis wrote: > On 11/15/20 9:17 AM, Greg Kroah-Hartman wrote: > > On Sun, Nov 15, 2020 at 03:53:16PM +0100, Emmanouil Perselis wrote: > >> This patch fixes the warning "static const char * array should > >> probably be static const char * const" in > >> drivers/staging/greybus/audio_manager_module.c > > >> I think Greg's patch bot is telling you that you need > >> to carbon-copy the mailing list on your patch submission, > >> not just address it to the maintainers. > > Added addresses to carbon copy. Do you think this is the correct way to submit a patch that doesn't have to be hand-edited in order to apply it? Please make it match other submitted patches, but most importantly, actually test-build your changes to ensure that they are correct. thanks, greg k-h From mchehab+huawei at kernel.org Tue Nov 17 06:55:42 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Tue, 17 Nov 2020 07:55:42 +0100 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: <20201116153106.GA1682049@bogus> References: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> <20201116153106.GA1682049@bogus> Message-ID: <20201117075542.734f429b@coco.lan> Em Mon, 16 Nov 2020 09:31:06 -0600 Rob Herring escreveu: > On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote: > > The phy USB3 driver for Hisilicon 970 (hi3670) is ready > > for mainstream. Mode it from staging into the main driver's > > s/Mode/Move/ > > > phy/ directory. > > > > Signed-off-by: Mauro Carvalho Chehab > > --- > > .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ > > MAINTAINERS | 9 +- > > drivers/phy/hisilicon/Kconfig | 10 + > > drivers/phy/hisilicon/Makefile | 1 + > > drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ > > drivers/staging/hikey9xx/Kconfig | 11 - > > drivers/staging/hikey9xx/Makefile | 2 - > > drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ > > drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- > > I assume this is only a move? Use '-M' option. This is a move, although I explicitly disabled -M on this series, as both the driver code and DT may still require some review, as those patches are for subsystems that I haven't made any relevant contributions so far. Thanks, Mauro From krzk at kernel.org Tue Nov 17 07:37:43 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Tue, 17 Nov 2020 08:37:43 +0100 Subject: [RFC 2/3] ARM: sunxi: do not select COMMON_CLK to fix builds In-Reply-To: References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-3-krzk@kernel.org> Message-ID: <20201117073743.GB3436@kozik-lap> On Mon, Nov 16, 2020 at 10:36:12PM -0600, Samuel Holland wrote: > On 11/15/20 11:09 AM, Krzysztof Kozlowski wrote: > > COMMON_CLK is a user-selectable option with its own dependencies. The > > most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers > > should not select COMMON_CLK because they will create a dependency cycle > > and build failures. For example on MIPS a configuration with COMMON_CLK > > (selected by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (selected by > > SOC_RT305X) is possible: > > Ah, that makes sense. > > > > > WARNING: unmet direct dependencies detected for COMMON_CLK > > Depends on [n]: !HAVE_LEGACY_CLK [=y] > > Selected by [y]: > > - SND_SUN8I_CODEC [=y] && SOUND [=y] && !UML && SND [=y] && SND_SOC [=y] && > > (ARCH_SUNXI || COMPILE_TEST [=y]) && OF [=y] && (MACH_SUN8I || ARM64 && ARCH_SUNXI || COMPILE_TEST [=y]) > > > > /usr/bin/mips-linux-gnu-ld: drivers/clk/clk.o: in function `clk_set_rate': > > (.text+0xaeb4): multiple definition of `clk_set_rate'; arch/mips/ralink/clk.o:(.text+0x88): first defined here > > > > Signed-off-by: Krzysztof Kozlowski > > --- > > arch/arm/mach-sunxi/Kconfig | 1 + > > sound/soc/sunxi/Kconfig | 2 +- > > 2 files changed, 2 insertions(+), 1 deletion(-) > > > > diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig > > index eeadb1a4dcfe..4d9f9b6d329d 100644 > > --- a/arch/arm/mach-sunxi/Kconfig > > +++ b/arch/arm/mach-sunxi/Kconfig > > @@ -4,6 +4,7 @@ menuconfig ARCH_SUNXI > > depends on ARCH_MULTI_V5 || ARCH_MULTI_V7 > > select ARCH_HAS_RESET_CONTROLLER > > select CLKSRC_MMIO > > + select COMMON_CLK > > This is not necessary, since ARCH_SUNXI depends (through ARCH_MULTI_V{5,7}) on > ARCH_MULTIPLATFORM, which selects COMMON_CLK already. Thanks. I'll send a v2 with changes and your review. Best regards, Krzysztof From mchehab+huawei at kernel.org Tue Nov 17 08:08:22 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Tue, 17 Nov 2020 09:08:22 +0100 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: <20201116183833.GC4739@sirena.org.uk> References: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> <20201116183833.GC4739@sirena.org.uk> Message-ID: <20201117090724.4ade833a@coco.lan> Hi Mark, Em Mon, 16 Nov 2020 18:38:33 +0000 Mark Brown escreveu: > > This driver is ready for mainstream. Move it out of staging. > > There's quite a few issues here, to be honest I'm disappointed some of > them weren't caught during staging review, this needs fairly substantial > work and there's signs that this also applies to at least the MFD > portion. > ... > > +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev, > > + struct device_node *np, > > + struct hi6421_spmi_pmic *pmic) > > +{ > > This probe code looks very different to other regulator drivers, this > alone should have been a warning that the driver needs some substantial > refactoring here. As indicated information about what regulators are > present on devices and their properties should be in the driver not the > DT, the driver should just be able to register them unconditionally and > use of_match and regulators_node to allow the core to find any > constraints that are provided by the platform. Let me reply to this before handling the other issues you pointed, as this one is related to some design decisions I had to make for this driver to properly work upstream. FYI, all documentation I have about this board is at: https://www.96boards.org/documentation/consumer/hikey/hikey970/ - The setup for MFD/regulator is different than almost all other regulator drivers currently upstreamed[1]. The PM part of Hikey970 is based on a master/slave SPMI bus. Each bus can have up to 16 PM chips connected into it. It means that, for the regulator driver to work, two drivers should be probed first: the SPMI bus controller driver (hisi-spmi-controller.c) and the SPMI bus client driver, which is at the MFD driver(hi6421-spmi-pmic.c). Only after having both probed, the regulator driver can be probed. Also, as all the communication between the PM chip and the SoC happens via a single serial bus, there's no sense on probing the regulators in parallel. That's mainly the reason why I opted to serialize the probe inside hi6421v600-regulator.c. The relevant changeset that ensures that everything is probed the right way is this one: 75937f8f961e ("staging: regulator: hi6421v600-regulator: change the binding logic") Without such change, the driver doesn't work upstream, as the regulator driver ends by being probed before the bus client driver (MFD). There's a second reason, though: when letting regulator probe to happen in parallel, the LDOs got probed on a random order, which makes more difficult to debug the driver, as the LDO numbering may not be following the LDO name, making harder to debug the drivers that depend on regulator support. Thanks, Mauro [1] The only other drivers for SPMI bus are from some Qualcomm based boards - those seem to be using a different setup. From Christian.Gromm at microchip.com Tue Nov 17 08:08:50 2020 From: Christian.Gromm at microchip.com (Christian.Gromm at microchip.com) Date: Tue, 17 Nov 2020 08:08:50 +0000 Subject: [PATCH v2] drivers: most: add ALSA sound driver In-Reply-To: <20201110084826.GE29398@kadam> References: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> <20201110084826.GE29398@kadam> Message-ID: <564d35a4fc32866f91f5bf3fb1bb16a5c67b3d9e.camel@microchip.com> On Tue, 2020-11-10 at 11:48 +0300, Dan Carpenter wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > On Fri, Nov 06, 2020 at 05:30:54PM +0100, Christian Gromm wrote: > > +static struct list_head adpt_list; > > + > > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > > + SNDRV_PCM_INFO_MMAP_VALID | \ > > + SNDRV_PCM_INFO_BATCH | \ > > + SNDRV_PCM_INFO_INTERLEAVED | \ > > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > > + > > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < (bytes / 2)) { > > + dest[i] = swab16(source[i]); > > + i++; > > + } > > +} > > + > > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < bytes - 2) { > > Can bytes ever be zero? If so then this will corrupt memory and crash. > > Generally "int i;" is less risky than "unsigned int i;". Of course, I > recently almost introduced a situation where we were copying up to > ULONG_MAX bytes so there are times when iterators should be size_t so > that does happen. It could be buggy either way is what I'm saying but > generally "unsigned int i;" is more often buggy. > > > + dest[i] = source[i + 2]; > > + dest[i + 1] = source[i + 1]; > > + dest[i + 2] = source[i]; > > + i += 3; > > + } > > +} > > + > > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) > > +{ > > + unsigned int i = 0; > > + > > + while (i < bytes / 4) { > > + dest[i] = swab32(source[i]); > > + i++; > > + } > > +} > > + > > +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) > > +{ > > + memcpy(most, alsa, bytes); > > +} > > + > > +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy16(most, alsa, bytes); > > +} > > + > > +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy24(most, alsa, bytes); > > +} > > + > > +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy32(most, alsa, bytes); > > +} > > + > > +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) > > +{ > > + memcpy(alsa, most, bytes); > > +} > > + > > +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy16(alsa, most, bytes); > > +} > > + > > +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy24(alsa, most, bytes); > > +} > > + > > +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) > > +{ > > + swap_copy32(alsa, most, bytes); > > +} > > + > > +/** > > + * get_channel - get pointer to channel > > + * @iface: interface structure > > + * @channel_id: channel ID > > + * > > + * This traverses the channel list and returns the channel matching the > > + * ID and interface. > > + * > > + * Returns pointer to channel on success or NULL otherwise. > > + */ > > +static struct channel *get_channel(struct most_interface *iface, > > + int channel_id) > > +{ > > + struct sound_adapter *adpt = iface->priv; > > + struct channel *channel, *tmp; > > + > > + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { > > + if ((channel->iface == iface) && (channel->id == channel_id)) > > + return channel; > > No need to use the _safe() version of this loop macro. You're not > freeing anything. My concern is that sometimes people think the _safe() > has something to do with locking and it does not. > > > + } > > + return NULL; > > +} > > + > > [ Snip ] > > > +/** > > + * audio_probe_channel - probe function of the driver module > > + * @iface: pointer to interface instance > > + * @channel_id: channel index/ID > > + * @cfg: pointer to actual channel configuration > > + * @arg_list: string that provides the name of the device to be created in /dev > > + * plus the desired audio resolution > > + * > > + * Creates sound card, pcm device, sets pcm ops and registers sound card. > > + * > > + * Returns 0 on success or error code otherwise. > > + */ > > +static int audio_probe_channel(struct most_interface *iface, int channel_id, > > + struct most_channel_config *cfg, > > + char *device_name, char *arg_list) > > +{ > > + struct channel *channel; > > + struct sound_adapter *adpt; > > + struct snd_pcm *pcm; > > + int playback_count = 0; > > + int capture_count = 0; > > + int ret; > > + int direction; > > + u16 ch_num; > > + char *sample_res; > > + char arg_list_cpy[STRING_SIZE]; > > + > > + if (cfg->data_type != MOST_CH_SYNC) { > > + pr_err("Incompatible channel type\n"); > > + return -EINVAL; > > + } > > + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); > > + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); > > + if (ret < 0) > > + return ret; > > + > > + list_for_each_entry(adpt, &adpt_list, list) { > > + if (adpt->iface != iface) > > + continue; > > + if (adpt->registered) > > + return -ENOSPC; > > + adpt->pcm_dev_idx++; > > + goto skip_adpt_alloc; > > It's weird how if the "channel = " allocation fails, then we free this > "adpt" which we didn't allocate. We actually did allocate it in a previous call to this function. Otherwise we would not jump to the skip_adpt_alloc label. And if we don't jump there, we are allocating it right away. thanks, Chris From dingxiang at cmss.chinamobile.com Tue Nov 17 08:10:58 2020 From: dingxiang at cmss.chinamobile.com (Ding Xiang) Date: Tue, 17 Nov 2020 16:10:58 +0800 Subject: [PATCH] media: atomisp: remove redundant NULL check of "params" Message-ID: <20201117081058.673291-1-dingxiang@cmss.chinamobile.com> The check result of (!A || (A && B)) is equivalent to (!A || B), so remove redundant NULL check of "params" Signed-off-by: Ding Xiang --- drivers/staging/media/atomisp/pci/sh_css_params.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/sh_css_params.c b/drivers/staging/media/atomisp/pci/sh_css_params.c index 24fc497bd491..9eb02f463eba 100644 --- a/drivers/staging/media/atomisp/pci/sh_css_params.c +++ b/drivers/staging/media/atomisp/pci/sh_css_params.c @@ -4649,10 +4649,8 @@ ia_css_dvs2_6axis_config_allocate(const struct ia_css_stream *stream) params = stream->isp_params_configs; /* Backward compatibility by default consider pipe as Video*/ - if (!params || (params && - !params->pipe_dvs_6axis_config[IA_CSS_PIPE_ID_VIDEO])) { + if (!params || !params->pipe_dvs_6axis_config[IA_CSS_PIPE_ID_VIDEO]) goto err; - } dvs_config = kvcalloc(1, sizeof(struct ia_css_dvs_6axis_config), GFP_KERNEL); -- 2.28.0 From mchehab+huawei at kernel.org Tue Nov 17 08:38:30 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Tue, 17 Nov 2020 09:38:30 +0100 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: <20201116183833.GC4739@sirena.org.uk> References: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> <20201116183833.GC4739@sirena.org.uk> Message-ID: <20201117093830.29861118@coco.lan> Em Mon, 16 Nov 2020 18:38:33 +0000 Mark Brown escreveu: > On Mon, Nov 16, 2020 at 01:59:30PM +0100, Mauro Carvalho Chehab wrote: > > > This driver is ready for mainstream. Move it out of staging. > > There's quite a few issues here, to be honest I'm disappointed some of > them weren't caught during staging review, this needs fairly substantial > work and there's signs that this also applies to at least the MFD > portion. > > This also appears to be missing a DT binding document, binding > documentation is required for anything with DT support. The DT binding is documented on patch 3/8, together with MFD. As there's just one compatible for MFD and regulators altogether, I opted to have just one DT binding document for both. > > > +config REGULATOR_HI6421V600 > > + tristate "HiSilicon Hi6421v600 PMIC voltage regulator support" > > + depends on MFD_HI6421_SPMI && OF > > + depends on REGULATOR > > This is inside an if REGULATOR block, as with all the other regulator > drivers it doesn't need a dependency on REGULATOR. I'll drop it. This was needed while this was inside staging. > > > --- /dev/null > > +++ b/drivers/regulator/hi6421v600-regulator.c > > @@ -0,0 +1,478 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* > > + * Device driver for regulators in Hisi IC > > Please make the entire comment a C++ one so things look more > intentional. Ok. > > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > Are we sure about *all* these includes? I'll double check and do some cleanups. > > > +#define rdev_dbg(rdev, fmt, arg...) \ > > + pr_debug("%s: %s: " fmt, (rdev)->desc->name, __func__, ##arg) > > If it is useful to copy this then put it in a header rather than > cut'n'pasting it. I'm not sure I see a pressing need for most of the > trace here, it looks to be duplicating a lot of things the core does for > you. I'll cleanup the debug messages, and place this on a header. Due to SPMI bus, the standard debug macros don't work fine on this file. > > > +static DEFINE_MUTEX(enable_mutex); > > Drivers shouldn't be declaring global variables, if this is required it > should be allocated in driver data. I'll try to see a better place for this, but in this case, the mutex should be global anyway, as the access to the SPMI bus should be serialized. I suspect that a change like that will likely require touching the SPMI bus core, but I can't foresee the side effects to the Qualcomm SPMI drivers that would likely have their own ways to serialize access to the bus. > > > +/* > > + * helper function to ensure when it returns it is at least 'delay_us' > > + * microseconds after 'since'. > > + */ > > + > > +static int hi6421_spmi_regulator_is_enabled(struct regulator_dev *rdev) > > The helper function appears to have been removed? I'll drop the comment. > > > +{ > > + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); > > + struct hi6421_spmi_pmic *pmic = sreg->pmic; > > + u32 reg_val; > > + > > + reg_val = hi6421_spmi_pmic_read(pmic, rdev->desc->enable_reg); > > + > > + rdev_dbg(rdev, > > + "enable_reg=0x%x, val= 0x%x, enable_state=%d\n", > > + rdev->desc->enable_reg, > > + reg_val, (reg_val & rdev->desc->enable_mask)); > > + > > + return ((reg_val & rdev->desc->enable_mask) != 0); > > +} > > It looks like it would be less code overall to just implement a regmap > for the MFD, even if it were only used in this driver - almost > everything in here is just a carbon copy of standard helpers that the > core provides for regmap devices. Doing it in the MFD would be more > idiomatic for everything though. I tried to use regmap for this driver while porting it from Linaro's OOT to upstream, but it turns that adding support for it is not trivial. I suspect that, just like I2C has their own set of regmap functions (regmap_init_i2c, devm_regmap_init_i2c), if we want to properly support regmap, we need first to add a SPMI variant to it, as the locking should be bus-aware. > > > +static int hi6421_spmi_regulator_enable(struct regulator_dev *rdev) > > +{ > > + struct hi6421v600_regulator *sreg = rdev_get_drvdata(rdev); > > + struct hi6421_spmi_pmic *pmic = sreg->pmic; > > + > > + /* cannot enable more than one regulator at one time */ > > + mutex_lock(&enable_mutex); > > + usleep_range(HISI_REGS_ENA_PROTECT_TIME, > > + HISI_REGS_ENA_PROTECT_TIME + 1000); > > + > > + /* set enable register */ > > + rdev_dbg(rdev, > > + "off_on_delay=%d us, enable_reg=0x%x, enable_mask=0x%x\n", > > + rdev->desc->off_on_delay, rdev->desc->enable_reg, > > + rdev->desc->enable_mask); > > + > > + hi6421_spmi_pmic_rmw(pmic, rdev->desc->enable_reg, > > + rdev->desc->enable_mask, > > + rdev->desc->enable_mask); > > This is the one operation which is doing anything unusual and which I'd > expect to be open coded in the driver - obviously this is a pretty > simplistic implementation but it will work though as indicated above it > shouldn't be using a global, the mutex should be in driver data. I > guess you could use the mutex to protect a timestamp and use that to > figure out if a delay is actually needed? I'll rework this logic. > > +static int hi6421_spmi_dt_parse(struct platform_device *pdev, > > + struct hi6421v600_regulator *sreg, > > + struct regulator_desc *rdesc) > > +{ > > + struct device *dev = &pdev->dev; > > + struct device_node *np = dev->of_node; > > + unsigned int *v_table; > > + int ret; > > + > > + ret = of_property_read_u32(np, "reg", &rdesc->enable_reg); > > + if (ret) { > > + dev_err(dev, "missing reg property\n"); > > + return ret; > > + } > > + > > + ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg); > > There is no way this stuff should be being parsed out of DT, we should > know the register map for the device and what regulators it has based > purely off knowing what device we have. Baking the register map into > the ABI is bad practice, it prevents us from improving our support for > the hardware without going and updating people's DTs. Well, I can move the existing registers out of DT, but, as I don't have any datasheet for this device, it means that I can implement there only a subset of the available LDOs. So, from the 36 LDOs that this chip support, we only know the registers for 8 of them: ldo3, ldo4, ldo9, ldo15, ldo16, ldo17, ldo33 and ldo34. > > + /* > > + * Not all regulators work on idle mode > > + */ > > + ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask); > > + if (ret) { > > + dev_dbg(dev, "LDO doesn't support economy mode.\n"); > > + sreg->eco_mode_mask = 0; > > + sreg->eco_uA = 0; > > + } else { > > + ret = of_property_read_u32(np, "eco-microamp", &sreg->eco_uA); > > There's no conditional code to not register the mode operations if the > mode information is not available (and again this should be done based > on knowing the properties of the device, this is unlikely to be system > dependent). This is the same case as before: as we don't have any datasheets, I only know what's there at the DT for just one device (Hikey 970). Again, we could hardcode those assuming Hikey 970 settings, but, if some other device using the same chip will ever be added, and they use some different configuration then we may face some backward-compatibility issues. > > > +static int hi6421_spmi_regulator_probe_ldo(struct platform_device *pdev, > > + struct device_node *np, > > + struct hi6421_spmi_pmic *pmic) > > +{ > > This probe code looks very different to other regulator drivers, this > alone should have been a warning that the driver needs some substantial > refactoring here. As indicated information about what regulators are > present on devices and their properties should be in the driver not the > DT, the driver should just be able to register them unconditionally and > use of_match and regulators_node to allow the core to find any > constraints that are provided by the platform. (already commented on a separate e-mail) > > > + constraint->valid_modes_mask = REGULATOR_MODE_NORMAL; > > + if (sreg->eco_mode_mask) { > > + constraint->valid_modes_mask |= REGULATOR_MODE_IDLE; > > + constraint->valid_ops_mask |= REGULATOR_CHANGE_MODE; > > + } > > This is absolutely not OK, a regulator driver should *not* be modifying > the constraints that the machine has set. If it is safe to change modes > on a platform and the system integrator wants to do that then they will > set the constraints appropriately, there is no way the regulator driver > can tell what is appropriate on a given system. The fact that the > driver is including machine.h at all ought to have been an indicator > that there's an abstraction problem here. Ok. Where such constraints should be instead? at the Hikey 970 DT file? Thanks, Mauro From nami at 4sasa.xyz Tue Nov 17 08:40:36 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Tue, 17 Nov 2020 16:40:36 +0800 Subject: Greetings Dear Beloved: Message-ID: <20201117084126.40D3620386@silver.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Melvida Bullock Email:?melvbullockzone123 at gmail.com From dan.carpenter at oracle.com Tue Nov 17 08:41:46 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Tue, 17 Nov 2020 11:41:46 +0300 Subject: [PATCH v2] drivers: most: add ALSA sound driver In-Reply-To: <564d35a4fc32866f91f5bf3fb1bb16a5c67b3d9e.camel@microchip.com> References: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> <20201110084826.GE29398@kadam> <564d35a4fc32866f91f5bf3fb1bb16a5c67b3d9e.camel@microchip.com> Message-ID: <20201117084145.GB29398@kadam> On Tue, Nov 17, 2020 at 08:08:50AM +0000, Christian.Gromm at microchip.com wrote: > On Tue, 2020-11-10 at 11:48 +0300, Dan Carpenter wrote: > > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > > > On Fri, Nov 06, 2020 at 05:30:54PM +0100, Christian Gromm wrote: > > > +static struct list_head adpt_list; > > > + > > > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > > > + SNDRV_PCM_INFO_MMAP_VALID | \ > > > + SNDRV_PCM_INFO_BATCH | \ > > > + SNDRV_PCM_INFO_INTERLEAVED | \ > > > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > > > + > > > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < (bytes / 2)) { > > > + dest[i] = swab16(source[i]); > > > + i++; > > > + } > > > +} > > > + > > > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < bytes - 2) { > > > > Can bytes ever be zero? If so then this will corrupt memory and crash. > > > > Generally "int i;" is less risky than "unsigned int i;". Of course, I > > recently almost introduced a situation where we were copying up to > > ULONG_MAX bytes so there are times when iterators should be size_t so > > that does happen. It could be buggy either way is what I'm saying but > > generally "unsigned int i;" is more often buggy. > > > > > + dest[i] = source[i + 2]; > > > + dest[i + 1] = source[i + 1]; > > > + dest[i + 2] = source[i]; > > > + i += 3; > > > + } > > > +} > > > + > > > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) > > > +{ > > > + unsigned int i = 0; > > > + > > > + while (i < bytes / 4) { > > > + dest[i] = swab32(source[i]); > > > + i++; > > > + } > > > +} > > > + > > > +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + memcpy(most, alsa, bytes); > > > +} > > > + > > > +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy16(most, alsa, bytes); > > > +} > > > + > > > +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy24(most, alsa, bytes); > > > +} > > > + > > > +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy32(most, alsa, bytes); > > > +} > > > + > > > +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + memcpy(alsa, most, bytes); > > > +} > > > + > > > +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy16(alsa, most, bytes); > > > +} > > > + > > > +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy24(alsa, most, bytes); > > > +} > > > + > > > +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) > > > +{ > > > + swap_copy32(alsa, most, bytes); > > > +} > > > + > > > +/** > > > + * get_channel - get pointer to channel > > > + * @iface: interface structure > > > + * @channel_id: channel ID > > > + * > > > + * This traverses the channel list and returns the channel matching the > > > + * ID and interface. > > > + * > > > + * Returns pointer to channel on success or NULL otherwise. > > > + */ > > > +static struct channel *get_channel(struct most_interface *iface, > > > + int channel_id) > > > +{ > > > + struct sound_adapter *adpt = iface->priv; > > > + struct channel *channel, *tmp; > > > + > > > + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { > > > + if ((channel->iface == iface) && (channel->id == channel_id)) > > > + return channel; > > > > No need to use the _safe() version of this loop macro. You're not > > freeing anything. My concern is that sometimes people think the _safe() > > has something to do with locking and it does not. > > > > > + } > > > + return NULL; > > > +} > > > + > > > > [ Snip ] > > > > > +/** > > > + * audio_probe_channel - probe function of the driver module > > > + * @iface: pointer to interface instance > > > + * @channel_id: channel index/ID > > > + * @cfg: pointer to actual channel configuration > > > + * @arg_list: string that provides the name of the device to be created in /dev > > > + * plus the desired audio resolution > > > + * > > > + * Creates sound card, pcm device, sets pcm ops and registers sound card. > > > + * > > > + * Returns 0 on success or error code otherwise. > > > + */ > > > +static int audio_probe_channel(struct most_interface *iface, int channel_id, > > > + struct most_channel_config *cfg, > > > + char *device_name, char *arg_list) > > > +{ > > > + struct channel *channel; > > > + struct sound_adapter *adpt; > > > + struct snd_pcm *pcm; > > > + int playback_count = 0; > > > + int capture_count = 0; > > > + int ret; > > > + int direction; > > > + u16 ch_num; > > > + char *sample_res; > > > + char arg_list_cpy[STRING_SIZE]; > > > + > > > + if (cfg->data_type != MOST_CH_SYNC) { > > > + pr_err("Incompatible channel type\n"); > > > + return -EINVAL; > > > + } > > > + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); > > > + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); > > > + if (ret < 0) > > > + return ret; > > > + > > > + list_for_each_entry(adpt, &adpt_list, list) { > > > + if (adpt->iface != iface) > > > + continue; > > > + if (adpt->registered) > > > + return -ENOSPC; > > > + adpt->pcm_dev_idx++; > > > + goto skip_adpt_alloc; > > > > It's weird how if the "channel = " allocation fails, then we free this > > "adpt" which we didn't allocate. > > We actually did allocate it in a previous call to this function. > Otherwise we would not jump to the skip_adpt_alloc label. And if > we don't jump there, we are allocating it right away. > I mean obviously everyone can see that it was allocated by an earlier call to the function. What I mean is that it's a layering violation. The unwind would normally be done in the caller. Is it okay to delete the adapter without emptying the mdev_link_list as well? regards, dan carpenter From vkoul at kernel.org Tue Nov 17 09:51:48 2020 From: vkoul at kernel.org (Vinod Koul) Date: Tue, 17 Nov 2020 15:21:48 +0530 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: <20201117075542.734f429b@coco.lan> References: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> <20201116153106.GA1682049@bogus> <20201117075542.734f429b@coco.lan> Message-ID: <20201117095148.GE50232@vkoul-mobl> On 17-11-20, 07:55, Mauro Carvalho Chehab wrote: > Em Mon, 16 Nov 2020 09:31:06 -0600 > Rob Herring escreveu: > > > On Mon, Nov 16, 2020 at 01:59:27PM +0100, Mauro Carvalho Chehab wrote: > > > The phy USB3 driver for Hisilicon 970 (hi3670) is ready > > > for mainstream. Mode it from staging into the main driver's > > > > s/Mode/Move/ > > > > > phy/ directory. > > > > > > Signed-off-by: Mauro Carvalho Chehab > > > --- > > > .../bindings/phy/phy-hi3670-usb3.yaml | 72 ++ > > > MAINTAINERS | 9 +- > > > drivers/phy/hisilicon/Kconfig | 10 + > > > drivers/phy/hisilicon/Makefile | 1 + > > > drivers/phy/hisilicon/phy-hi3670-usb3.c | 671 ++++++++++++++++++ > > > drivers/staging/hikey9xx/Kconfig | 11 - > > > drivers/staging/hikey9xx/Makefile | 2 - > > > drivers/staging/hikey9xx/phy-hi3670-usb3.c | 671 ------------------ > > > drivers/staging/hikey9xx/phy-hi3670-usb3.yaml | 72 -- > > > > I assume this is only a move? Use '-M' option. > > This is a move, although I explicitly disabled -M on this series, as both > the driver code and DT may still require some review, as those patches > are for subsystems that I haven't made any relevant contributions > so far. I for one am appreciating the intent here, it helps to review the patch coming in from staging Thanks -- ~Vinod From Christian.Gromm at microchip.com Tue Nov 17 10:04:01 2020 From: Christian.Gromm at microchip.com (Christian.Gromm at microchip.com) Date: Tue, 17 Nov 2020 10:04:01 +0000 Subject: [PATCH v2] drivers: most: add ALSA sound driver In-Reply-To: <20201117084145.GB29398@kadam> References: <1604680254-17185-1-git-send-email-christian.gromm@microchip.com> <20201110084826.GE29398@kadam> <564d35a4fc32866f91f5bf3fb1bb16a5c67b3d9e.camel@microchip.com> <20201117084145.GB29398@kadam> Message-ID: <78cc59b31042f865e947a2c09a5d10cc60ddc01c.camel@microchip.com> On Tue, 2020-11-17 at 11:41 +0300, Dan Carpenter wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > On Tue, Nov 17, 2020 at 08:08:50AM +0000, Christian.Gromm at microchip.com wrote: > > On Tue, 2020-11-10 at 11:48 +0300, Dan Carpenter wrote: > > > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > > > > > On Fri, Nov 06, 2020 at 05:30:54PM +0100, Christian Gromm wrote: > > > > +static struct list_head adpt_list; > > > > + > > > > +#define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ > > > > + SNDRV_PCM_INFO_MMAP_VALID | \ > > > > + SNDRV_PCM_INFO_BATCH | \ > > > > + SNDRV_PCM_INFO_INTERLEAVED | \ > > > > + SNDRV_PCM_INFO_BLOCK_TRANSFER) > > > > + > > > > +static void swap_copy16(u16 *dest, const u16 *source, unsigned int bytes) > > > > +{ > > > > + unsigned int i = 0; > > > > + > > > > + while (i < (bytes / 2)) { > > > > + dest[i] = swab16(source[i]); > > > > + i++; > > > > + } > > > > +} > > > > + > > > > +static void swap_copy24(u8 *dest, const u8 *source, unsigned int bytes) > > > > +{ > > > > + unsigned int i = 0; > > > > + > > > > + while (i < bytes - 2) { > > > > > > Can bytes ever be zero? If so then this will corrupt memory and crash. > > > > > > Generally "int i;" is less risky than "unsigned int i;". Of course, I > > > recently almost introduced a situation where we were copying up to > > > ULONG_MAX bytes so there are times when iterators should be size_t so > > > that does happen. It could be buggy either way is what I'm saying but > > > generally "unsigned int i;" is more often buggy. > > > > > > > + dest[i] = source[i + 2]; > > > > + dest[i + 1] = source[i + 1]; > > > > + dest[i + 2] = source[i]; > > > > + i += 3; > > > > + } > > > > +} > > > > + > > > > +static void swap_copy32(u32 *dest, const u32 *source, unsigned int bytes) > > > > +{ > > > > + unsigned int i = 0; > > > > + > > > > + while (i < bytes / 4) { > > > > + dest[i] = swab32(source[i]); > > > > + i++; > > > > + } > > > > +} > > > > + > > > > +static void alsa_to_most_memcpy(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + memcpy(most, alsa, bytes); > > > > +} > > > > + > > > > +static void alsa_to_most_copy16(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy16(most, alsa, bytes); > > > > +} > > > > + > > > > +static void alsa_to_most_copy24(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy24(most, alsa, bytes); > > > > +} > > > > + > > > > +static void alsa_to_most_copy32(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy32(most, alsa, bytes); > > > > +} > > > > + > > > > +static void most_to_alsa_memcpy(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + memcpy(alsa, most, bytes); > > > > +} > > > > + > > > > +static void most_to_alsa_copy16(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy16(alsa, most, bytes); > > > > +} > > > > + > > > > +static void most_to_alsa_copy24(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy24(alsa, most, bytes); > > > > +} > > > > + > > > > +static void most_to_alsa_copy32(void *alsa, void *most, unsigned int bytes) > > > > +{ > > > > + swap_copy32(alsa, most, bytes); > > > > +} > > > > + > > > > +/** > > > > + * get_channel - get pointer to channel > > > > + * @iface: interface structure > > > > + * @channel_id: channel ID > > > > + * > > > > + * This traverses the channel list and returns the channel matching the > > > > + * ID and interface. > > > > + * > > > > + * Returns pointer to channel on success or NULL otherwise. > > > > + */ > > > > +static struct channel *get_channel(struct most_interface *iface, > > > > + int channel_id) > > > > +{ > > > > + struct sound_adapter *adpt = iface->priv; > > > > + struct channel *channel, *tmp; > > > > + > > > > + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { > > > > + if ((channel->iface == iface) && (channel->id == channel_id)) > > > > + return channel; > > > > > > No need to use the _safe() version of this loop macro. You're not > > > freeing anything. My concern is that sometimes people think the _safe() > > > has something to do with locking and it does not. > > > > > > > + } > > > > + return NULL; > > > > +} > > > > + > > > > > > [ Snip ] > > > > > > > +/** > > > > + * audio_probe_channel - probe function of the driver module > > > > + * @iface: pointer to interface instance > > > > + * @channel_id: channel index/ID > > > > + * @cfg: pointer to actual channel configuration > > > > + * @arg_list: string that provides the name of the device to be created in /dev > > > > + * plus the desired audio resolution > > > > + * > > > > + * Creates sound card, pcm device, sets pcm ops and registers sound card. > > > > + * > > > > + * Returns 0 on success or error code otherwise. > > > > + */ > > > > +static int audio_probe_channel(struct most_interface *iface, int channel_id, > > > > + struct most_channel_config *cfg, > > > > + char *device_name, char *arg_list) > > > > +{ > > > > + struct channel *channel; > > > > + struct sound_adapter *adpt; > > > > + struct snd_pcm *pcm; > > > > + int playback_count = 0; > > > > + int capture_count = 0; > > > > + int ret; > > > > + int direction; > > > > + u16 ch_num; > > > > + char *sample_res; > > > > + char arg_list_cpy[STRING_SIZE]; > > > > + > > > > + if (cfg->data_type != MOST_CH_SYNC) { > > > > + pr_err("Incompatible channel type\n"); > > > > + return -EINVAL; > > > > + } > > > > + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); > > > > + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); > > > > + if (ret < 0) > > > > + return ret; > > > > + > > > > + list_for_each_entry(adpt, &adpt_list, list) { > > > > + if (adpt->iface != iface) > > > > + continue; > > > > + if (adpt->registered) > > > > + return -ENOSPC; > > > > + adpt->pcm_dev_idx++; > > > > + goto skip_adpt_alloc; > > > > > > It's weird how if the "channel = " allocation fails, then we free this > > > "adpt" which we didn't allocate. > > > > We actually did allocate it in a previous call to this function. > > Otherwise we would not jump to the skip_adpt_alloc label. And if > > we don't jump there, we are allocating it right away. > > > > I mean obviously everyone can see that it was allocated by an earlier > call to the function. What I mean is that it's a layering violation. > The unwind would normally be done in the caller. > > Is it okay to delete the adapter without emptying the mdev_link_list > as well? > Not necessarily, as when we are at this point the setup is already messed up and needs to be reconfigured from scratch anyway. This involves the call to mdev_link_destroy_link_store() that cleans up everything. thanks, Chris > regards, > dan carpenter > From broonie at kernel.org Tue Nov 17 14:25:24 2020 From: broonie at kernel.org (Mark Brown) Date: Tue, 17 Nov 2020 14:25:24 +0000 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: <20201117090724.4ade833a@coco.lan> References: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> <20201116183833.GC4739@sirena.org.uk> <20201117090724.4ade833a@coco.lan> Message-ID: <20201117142523.GD5142@sirena.org.uk> On Tue, Nov 17, 2020 at 09:08:22AM +0100, Mauro Carvalho Chehab wrote: > Mark Brown escreveu: > > This probe code looks very different to other regulator drivers, this > > alone should have been a warning that the driver needs some substantial > > refactoring here. As indicated information about what regulators are > > present on devices and their properties should be in the driver not the > > DT, the driver should just be able to register them unconditionally and > > use of_match and regulators_node to allow the core to find any > > constraints that are provided by the platform. > The setup for MFD/regulator is different than almost all other > regulator drivers currently upstreamed[1]. It really shouldn't be doing anything unusual. > It means that, for the regulator driver to work, two drivers > should be probed first: the SPMI bus controller driver > (hisi-spmi-controller.c) and the SPMI bus client driver, which is > at the MFD driver(hi6421-spmi-pmic.c). > Only after having both probed, the regulator driver can be > probed. This is totally fine and very common for drivers in general, a combination of probe deferral and fw_devlink exists to sort this stuff out. > Also, as all the communication between the PM chip > and the SoC happens via a single serial bus, there's no > sense on probing the regulators in parallel. > That's mainly the reason why I opted to serialize the probe > inside hi6421v600-regulator.c. I can't think of a regulator driver that doesn't have an entirly serialized probe routine, that's not the issue. The issue is that almost nothing that the probe routine is doing is done by other regulator drivers. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From lkp at intel.com Tue Nov 17 14:28:43 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 17 Nov 2020 22:28:43 +0800 Subject: [PATCH 2/8] spmi: hi6421-spmi-pmic: move driver from staging In-Reply-To: <7e01d84b31d561fa4df1d42369e4222f4a41a8d3.1605530560.git.mchehab+huawei@kernel.org> References: <7e01d84b31d561fa4df1d42369e4222f4a41a8d3.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <202011172204.sz98GuOL-lkp@intel.com> Hi Mauro, I love your patch! Perhaps something to improve: [auto build test WARNING on linus/master] [also build test WARNING on v5.10-rc4 next-20201117] [cannot apply to staging/staging-testing robh/for-next lee-mfd/for-mfd-next] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Mauro-Carvalho-Chehab/Move-Hikey-970-USB-support-out-of-staging-and-add-DT/20201116-210334 base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 09162bc32c880a791c6c0668ce0745cf7958f576 config: x86_64-randconfig-s022-20201115 (attached as .config) compiler: gcc-9 (Debian 9.3.0-15) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-107-gaf3512a6-dirty # https://github.com/0day-ci/linux/commit/b972250f20fc571defa4b23c9cc959df61eb0803 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Mauro-Carvalho-Chehab/Move-Hikey-970-USB-support-out-of-staging-and-add-DT/20201116-210334 git checkout b972250f20fc571defa4b23c9cc959df61eb0803 # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot "sparse warnings: (new ones prefixed by >>)" >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:164:24: sparse: sparse: cast to restricted __be32 >> drivers/spmi/hisi-spmi-controller.c:239:25: sparse: sparse: cast from restricted __be32 vim +164 drivers/spmi/hisi-spmi-controller.c 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 110 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 111 static int spmi_read_cmd(struct spmi_controller *ctrl, 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 112 u8 opc, u8 slave_id, u16 slave_addr, u8 *__buf, size_t bc) 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 113 { 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 114 struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 115 u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 116 unsigned long flags; 6af364501949d99 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 117 u8 *buf = __buf; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 118 u32 cmd, data; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 119 int rc; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 120 u8 op_code, i; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 121 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 122 if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 123 dev_err(&ctrl->dev, 4c6491a343e91a5 drivers/staging/hikey9xx/hisi-spmi-controller.c YueHaibing 2020-09-01 124 "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 125 SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 126 return -EINVAL; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 127 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 128 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 129 switch (opc) { 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 130 case SPMI_CMD_READ: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 131 op_code = SPMI_CMD_REG_READ; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 132 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 133 case SPMI_CMD_EXT_READ: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 134 op_code = SPMI_CMD_EXT_REG_READ; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 135 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 136 case SPMI_CMD_EXT_READL: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 137 op_code = SPMI_CMD_EXT_REG_READ_L; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 138 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 139 default: 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 140 dev_err(&ctrl->dev, "invalid read cmd 0x%x\n", opc); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 141 return -EINVAL; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 142 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 143 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 144 cmd = SPMI_APB_SPMI_CMD_EN | 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 145 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 146 ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 147 ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | /* slvid */ 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 148 ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); /* slave_addr */ 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 149 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 150 spin_lock_irqsave(&spmi_controller->lock, flags); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 151 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 152 writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 153 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 154 rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 155 spmi_controller->base, slave_id, slave_addr); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 156 if (rc) 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 157 goto done; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 158 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 159 for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 160 data = readl(spmi_controller->base + chnl_ofst + 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 161 SPMI_SLAVE_OFFSET * slave_id + 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 162 SPMI_APB_SPMI_RDATA0_BASE_ADDR + 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 163 i * SPMI_PER_DATAREG_BYTE); 8788a30c12c7884 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 @164 data = be32_to_cpu((__be32)data); 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 165 if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 166 memcpy(buf, &data, sizeof(data)); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 167 buf += sizeof(data); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 168 } else { 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 169 memcpy(buf, &data, bc % SPMI_PER_DATAREG_BYTE); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 170 buf += (bc % SPMI_PER_DATAREG_BYTE); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 171 } 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 172 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 173 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 174 done: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 175 spin_unlock_irqrestore(&spmi_controller->lock, flags); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 176 if (rc) 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 177 dev_err(&ctrl->dev, 4c6491a343e91a5 drivers/staging/hikey9xx/hisi-spmi-controller.c YueHaibing 2020-09-01 178 "spmi read wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 179 opc, slave_id, slave_addr, bc + 1); 6af364501949d99 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 180 else 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 181 dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, read value: %*ph\n", 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 182 __func__, slave_id, slave_addr, (int)bc, __buf); 6af364501949d99 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 183 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 184 return rc; 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 185 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 186 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 187 static int spmi_write_cmd(struct spmi_controller *ctrl, 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 188 u8 opc, u8 slave_id, u16 slave_addr, const u8 *__buf, size_t bc) 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 189 { 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 190 struct spmi_controller_dev *spmi_controller = dev_get_drvdata(&ctrl->dev); 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 191 u32 chnl_ofst = SPMI_CHANNEL_OFFSET * spmi_controller->channel; 6af364501949d99 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 192 const u8 *buf = __buf; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 193 unsigned long flags; 8788a30c12c7884 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 194 u32 cmd, data; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 195 int rc; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 196 u8 op_code, i; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 197 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 198 if (bc > SPMI_CONTROLLER_MAX_TRANS_BYTES) { 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 199 dev_err(&ctrl->dev, 4c6491a343e91a5 drivers/staging/hikey9xx/hisi-spmi-controller.c YueHaibing 2020-09-01 200 "spmi_controller supports 1..%d bytes per trans, but:%zu requested\n", 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 201 SPMI_CONTROLLER_MAX_TRANS_BYTES, bc); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 202 return -EINVAL; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 203 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 204 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 205 switch (opc) { 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 206 case SPMI_CMD_WRITE: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 207 op_code = SPMI_CMD_REG_WRITE; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 208 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 209 case SPMI_CMD_EXT_WRITE: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 210 op_code = SPMI_CMD_EXT_REG_WRITE; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 211 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 212 case SPMI_CMD_EXT_WRITEL: 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 213 op_code = SPMI_CMD_EXT_REG_WRITE_L; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 214 break; 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 215 default: 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 216 dev_err(&ctrl->dev, "invalid write cmd 0x%x\n", opc); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 217 return -EINVAL; 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 218 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 219 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 220 cmd = SPMI_APB_SPMI_CMD_EN | 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 221 (op_code << SPMI_APB_SPMI_CMD_TYPE_OFFSET) | 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 222 ((bc - 1) << SPMI_APB_SPMI_CMD_LENGTH_OFFSET) | 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 223 ((slave_id & 0xf) << SPMI_APB_SPMI_CMD_SLAVEID_OFFSET) | 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 224 ((slave_addr & 0xffff) << SPMI_APB_SPMI_CMD_ADDR_OFFSET); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 225 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 226 /* Write data to FIFOs */ 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 227 spin_lock_irqsave(&spmi_controller->lock, flags); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 228 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 229 for (i = 0; bc > i * SPMI_PER_DATAREG_BYTE; i++) { 8788a30c12c7884 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 230 data = 0; 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 231 if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 232 memcpy(&data, buf, sizeof(data)); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 233 buf += sizeof(data); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 234 } else { 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 235 memcpy(&data, buf, bc % SPMI_PER_DATAREG_BYTE); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 236 buf += (bc % SPMI_PER_DATAREG_BYTE); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 237 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 238 8788a30c12c7884 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 @239 writel((u32)cpu_to_be32(data), 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 240 spmi_controller->base + chnl_ofst + 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 241 SPMI_APB_SPMI_WDATA0_BASE_ADDR + 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 242 SPMI_PER_DATAREG_BYTE * i); 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 243 } 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 244 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 245 /* Start the transaction */ 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 246 writel(cmd, spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_CMD_BASE_ADDR); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 247 4d914a8c480c312 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 248 rc = spmi_controller_wait_for_done(&ctrl->dev, spmi_controller, 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 249 spmi_controller->base, slave_id, 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 250 slave_addr); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 251 spin_unlock_irqrestore(&spmi_controller->lock, flags); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 252 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 253 if (rc) 4c6491a343e91a5 drivers/staging/hikey9xx/hisi-spmi-controller.c YueHaibing 2020-09-01 254 dev_err(&ctrl->dev, "spmi write wait timeout op:0x%x slave_id:%d slave_addr:0x%x bc:%zu\n", 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 255 opc, slave_id, slave_addr, bc); 6af364501949d99 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 256 else 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 257 dev_dbg(&ctrl->dev, "%s: id:%d slave_addr:0x%x, wrote value: %*ph\n", 7f3ac6c502fd7ff drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 258 __func__, slave_id, slave_addr, (int)bc, __buf); 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 259 70f59c90c8199e8 drivers/staging/hikey9xx/hisi-spmi-controller.c Mayulong 2020-08-17 260 return rc; 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 261 } 2ea3f6a03b155f4 drivers/staging/hikey9xx/hisi-spmi-controller.c Mauro Carvalho Chehab 2020-08-17 262 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org -------------- next part -------------- A non-text attachment was scrubbed... Name: .config.gz Type: application/gzip Size: 36894 bytes Desc: not available URL: From broonie at kernel.org Tue Nov 17 15:10:11 2020 From: broonie at kernel.org (Mark Brown) Date: Tue, 17 Nov 2020 15:10:11 +0000 Subject: [PATCH 4/8] regulator: hi6421v600-regulator: move it from staging In-Reply-To: <20201117093830.29861118@coco.lan> References: <471362653f22a8748202c55babd2b462056a5797.1605530560.git.mchehab+huawei@kernel.org> <20201116183833.GC4739@sirena.org.uk> <20201117093830.29861118@coco.lan> Message-ID: <20201117151011.GE5142@sirena.org.uk> On Tue, Nov 17, 2020 at 09:38:30AM +0100, Mauro Carvalho Chehab wrote: > Mark Brown escreveu: > > This also appears to be missing a DT binding document, binding > > documentation is required for anything with DT support. > The DT binding is documented on patch 3/8, together with MFD. > As there's just one compatible for MFD and regulators altogether, > I opted to have just one DT binding document for both. I should've been copied on that patch then so the bindings can be reviewed. > > > +static DEFINE_MUTEX(enable_mutex); > > Drivers shouldn't be declaring global variables, if this is required it > > should be allocated in driver data. > I'll try to see a better place for this, but in this case, the > mutex should be global anyway, as the access to the SPMI bus > should be serialized. Surely the bus should be dealing with basic I/O serialisation? > > It looks like it would be less code overall to just implement a regmap > > for the MFD, even if it were only used in this driver - almost > > everything in here is just a carbon copy of standard helpers that the > > core provides for regmap devices. Doing it in the MFD would be more > > idiomatic for everything though. > I tried to use regmap for this driver while porting it from Linaro's > OOT to upstream, bkut it turns that adding support for it is not trivial. Could you expand on "not trivial" please? What did you try and what difficulties did you encounter? > I suspect that, just like I2C has their own set of regmap functions > (regmap_init_i2c, devm_regmap_init_i2c), if we want to properly support > regmap, we need first to add a SPMI variant to it, as the locking > should be bus-aware. drivers/base/regmap/regmap-spmi.c has been there since 2013, or if for some reason this device is doing something non-standard for the bus then the reg_read() and reg_write() operations can be used. > > > + ret = of_property_read_u32(np, "vsel-reg", &rdesc->vsel_reg); > > There is no way this stuff should be being parsed out of DT, we should > > know the register map for the device and what regulators it has based > > purely off knowing what device we have. Baking the register map into > > the ABI is bad practice, it prevents us from improving our support for > > the hardware without going and updating people's DTs. > Well, I can move the existing registers out of DT, but, as I don't > have any datasheet for this device, it means that I can implement > there only a subset of the available LDOs. So, from the 36 LDOs that > this chip support, we only know the registers for 8 of them: > ldo3, ldo4, ldo9, ldo15, ldo16, ldo17, ldo33 and ldo34. People will be free to submit patches adding additional functionality to the driver if they need it. > > > + /* > > > + * Not all regulators work on idle mode > > > + */ > > > + ret = of_property_read_u32(np, "idle-mode-mask", &sreg->eco_mode_mask); > > There's no conditional code to not register the mode operations if the > > mode information is not available (and again this should be done based > > on knowing the properties of the device, this is unlikely to be system > > dependent). > This is the same case as before: as we don't have any datasheets, > I only know what's there at the DT for just one device (Hikey 970). > Again, we could hardcode those assuming Hikey 970 settings, but, > if some other device using the same chip will ever be added, and > they use some different configuration then we may face some > backward-compatibility issues. I can't follow the logic here, sorry. If we have no idea how to configure something how would offering operations to configure that thing be useful? > > > + constraint->valid_modes_mask = REGULATOR_MODE_NORMAL; > > This is absolutely not OK, a regulator driver should *not* be modifying > > the constraints that the machine has set. If it is safe to change modes > > on a platform and the system integrator wants to do that then they will > > set the constraints appropriately, there is no way the regulator driver > > can tell what is appropriate on a given system. The fact that the > > driver is including machine.h at all ought to have been an indicator > > that there's an abstraction problem here. > Ok. Where such constraints should be instead? at the Hikey 970 DT > file? They should be configured whereever all the other constraints are configured by the platform, if that is DT then they should also be configured in DT. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From lkp at intel.com Wed Nov 18 04:25:19 2020 From: lkp at intel.com (kernel test robot) Date: Wed, 18 Nov 2020 12:25:19 +0800 Subject: [staging:staging-linus] BUILD SUCCESS 2dde2821b57f12fa8601d35d438b5e300fcbbe1d Message-ID: <5fb4a22f.i1txiZoUOMT2f5W6%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-linus branch HEAD: 2dde2821b57f12fa8601d35d438b5e300fcbbe1d Merge tag 'iio-fixes-for-5.10a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-linus elapsed time: 720m configs tested: 146 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig h8300 edosk2674_defconfig powerpc mpc8313_rdb_defconfig sh j2_defconfig sparc sparc64_defconfig mips bmips_be_defconfig ia64 zx1_defconfig powerpc mpc836x_rdk_defconfig xtensa generic_kc705_defconfig powerpc tqm8540_defconfig sh rsk7201_defconfig nios2 10m50_defconfig powerpc eiger_defconfig m68k mvme147_defconfig xtensa iss_defconfig mips ci20_defconfig s390 zfcpdump_defconfig openrisc alldefconfig powerpc xes_mpc85xx_defconfig arc haps_hs_defconfig arc vdk_hs38_smp_defconfig arm pxa910_defconfig sh sdk7786_defconfig powerpc tqm8555_defconfig powerpc tqm8560_defconfig arm orion5x_defconfig powerpc mgcoge_defconfig mips mtx1_defconfig m68k allmodconfig sh landisk_defconfig sh apsh4a3a_defconfig powerpc warp_defconfig arm u300_defconfig arm axm55xx_defconfig arm lpc18xx_defconfig arm moxart_defconfig arm u8500_defconfig m68k mac_defconfig arm alldefconfig arm mainstone_defconfig xtensa common_defconfig arm neponset_defconfig mips malta_kvm_guest_defconfig powerpc redwood_defconfig mips rb532_defconfig h8300 h8300h-sim_defconfig arc axs103_defconfig arc defconfig arm zeus_defconfig arm clps711x_defconfig sh ap325rxa_defconfig mips cu1000-neo_defconfig sh sh7785lcr_32bit_defconfig powerpc ps3_defconfig powerpc bluestone_defconfig sh microdev_defconfig powerpc ppc40x_defconfig nios2 defconfig powerpc adder875_defconfig m68k amcore_defconfig mips e55_defconfig sh migor_defconfig mips workpad_defconfig mips tb0219_defconfig powerpc ppa8548_defconfig mips cobalt_defconfig microblaze nommu_defconfig arm tct_hammer_defconfig mips mpc30x_defconfig powerpc skiroot_defconfig riscv defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k defconfig m68k allyesconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a006-20201117 i386 randconfig-a005-20201117 i386 randconfig-a001-20201117 i386 randconfig-a002-20201117 i386 randconfig-a004-20201117 i386 randconfig-a003-20201117 x86_64 randconfig-a015-20201115 x86_64 randconfig-a011-20201115 x86_64 randconfig-a014-20201115 x86_64 randconfig-a013-20201115 x86_64 randconfig-a016-20201115 x86_64 randconfig-a012-20201115 i386 randconfig-a012-20201117 i386 randconfig-a014-20201117 i386 randconfig-a016-20201117 i386 randconfig-a011-20201117 i386 randconfig-a015-20201117 i386 randconfig-a013-20201117 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a003-20201117 x86_64 randconfig-a005-20201117 x86_64 randconfig-a004-20201117 x86_64 randconfig-a002-20201117 x86_64 randconfig-a001-20201117 x86_64 randconfig-a006-20201117 x86_64 randconfig-a015-20201116 x86_64 randconfig-a011-20201116 x86_64 randconfig-a014-20201116 x86_64 randconfig-a013-20201116 x86_64 randconfig-a016-20201116 x86_64 randconfig-a012-20201116 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From huanggf at par.cse.nsysu.edu.tw Wed Nov 18 04:06:28 2020 From: huanggf at par.cse.nsysu.edu.tw (COCA COLA.) Date: Tue, 17 Nov 2020 20:06:28 -0800 Subject: COCA-COLA LOTTERY ORGANIZATION. Message-ID: <20201118060910.1288E867C8@whitealder.osuosl.org> COCA-COLA LOTTERY ORGANIZATION TICKET FREE/ONLINE E-MAIL ADDRESS WINNINGS DEPARTMENT. Greetings Winner, If you are the correct owner of this email address? If yes then be glad this day as the result of the Coca-Cola lotto online e-mail address free-ticket winning draws of July 2020 ,held in United States of America has just been released and we are glad to announce to you that your email address won you the sweepstakes in the first category and you are entitled to claim the sum of One Million Two Hundred And Fifty Thousand United States Dollars(US$1,250,000.00). Your email address was entered for the online draw on this ticket No: 546-373-66773 and won on this Lucky No: (14)-(8)-(5)-(19)-(28)-(12)-(30). On how to receive your won prize of US$1.250,000.00M. (One Million Two Hundred And Fifty Thousand United States Dollars Only) to enable Mr.James Curtise ascertain you as the rightful winner and receiver of the US$1.250,000.00M.Make sure you include the below listed information in your contact email to him. Your complete official names, country of origin and country of residence/work, contact telephone and mobile numbers, amount won,lucky numbers, date of draw. OPTIONAL: - [Sex, age, occupation and job title]. Just in case you are thinking of how you won without entering then know again that this very draw of the Coca-Cola Lottery Organization in which you have emerged as a winner was a free ticket online email address draws were thousands of email addresses was collected from almost all world wide websites and used for the online draws/sweepstakes and during winners selection your email address came out among the first ten which won you the lottery in the first winnings category and entitles you to claim the US$1,250,000.00 dollars. Yours Faithfully, Mr.James Curtise COCA-COLA LOTTERY ORGANIZATION. Online Winning Notification Department. Tel: +1-403-607-1548 From sboyd at kernel.org Wed Nov 18 07:41:57 2020 From: sboyd at kernel.org (Stephen Boyd) Date: Tue, 17 Nov 2020 23:41:57 -0800 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <20201115170950.304460-2-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-2-krzk@kernel.org> Message-ID: <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> Quoting Krzysztof Kozlowski (2020-11-15 09:09:48) > COMMON_CLK even though is a user-selectable symbol, is still selected by > multiple other config options. COMMON_CLK should not be used when > legacy clocks are provided by architecture, so it correctly depends on > !HAVE_LEGACY_CLK. > > However it is possible to create a config which selects both COMMON_CLK > (by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (by SOC_RT305X) which leads to Why is SND_SUN8I_CODEC selecting COMMON_CLK? Or really, why is SOC_RT305X selecting HAVE_LEGACY_CLK? From krzk at kernel.org Wed Nov 18 07:48:12 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Wed, 18 Nov 2020 08:48:12 +0100 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-2-krzk@kernel.org> <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> Message-ID: <20201118074812.GA5803@kozik-lap> On Tue, Nov 17, 2020 at 11:41:57PM -0800, Stephen Boyd wrote: > Quoting Krzysztof Kozlowski (2020-11-15 09:09:48) > > COMMON_CLK even though is a user-selectable symbol, is still selected by > > multiple other config options. COMMON_CLK should not be used when > > legacy clocks are provided by architecture, so it correctly depends on > > !HAVE_LEGACY_CLK. > > > > However it is possible to create a config which selects both COMMON_CLK > > (by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (by SOC_RT305X) which leads to > > Why is SND_SUN8I_CODEC selecting COMMON_CLK? Or really, why is > SOC_RT305X selecting HAVE_LEGACY_CLK? The SND_SUN8I_CODEC I fixed in following patch (I sent separately v2 of it). The SOC_RT305X select HAVE_LEGACY_CLK? because it is an old, Ralink platform, not converted to Common clock frm. Few clock operations are defined in: arch/mips/ralink/clk.c Best regards, Krzysztof From wanghai38 at huawei.com Wed Nov 18 10:37:24 2020 From: wanghai38 at huawei.com (Wang Hai) Date: Wed, 18 Nov 2020 18:37:24 +0800 Subject: [PATCH] staging: mfd: hi6421-spmi-pmic: fix error return code in hi6421_spmi_pmic_probe() Message-ID: <20201118103724.57451-1-wanghai38@huawei.com> Fix to return a negative error code from the error handling case instead of 0, as done elsewhere in this function. Fixes: 4524ac56cdca ("staging: mfd: add a PMIC driver for HiSilicon 6421 SPMI version") Reported-by: Hulk Robot Signed-off-by: Wang Hai --- drivers/staging/hikey9xx/hi6421-spmi-pmic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c index 64b30d263c8d..4f34a5282970 100644 --- a/drivers/staging/hikey9xx/hi6421-spmi-pmic.c +++ b/drivers/staging/hikey9xx/hi6421-spmi-pmic.c @@ -262,8 +262,10 @@ static int hi6421_spmi_pmic_probe(struct spmi_device *pdev) hi6421_spmi_pmic_irq_prc(pmic); pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL); - if (!pmic->irqs) + if (!pmic->irqs) { + ret = -ENOMEM; goto irq_malloc; + } pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0, &hi6421_spmi_domain_ops, pmic); -- 2.17.1 From dan.carpenter at oracle.com Wed Nov 18 11:12:24 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Wed, 18 Nov 2020 14:12:24 +0300 Subject: [PATCH] staging: mfd: hi6421-spmi-pmic: fix error return code in hi6421_spmi_pmic_probe() In-Reply-To: <20201118103724.57451-1-wanghai38@huawei.com> References: <20201118103724.57451-1-wanghai38@huawei.com> Message-ID: <20201118111224.GC29398@kadam> Not necessarily related to your patch but it should just return -ENOMEM instead of the "goto irq_malloc;". drivers/staging/hikey9xx/hi6421-spmi-pmic.c 251 if (!gpio_is_valid(pmic->gpio)) 252 return -EINVAL; 253 254 ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, "pmic"); 255 if (ret < 0) { 256 dev_err(dev, "failed to request gpio%d\n", pmic->gpio); 257 return ret; This is a direct return. 258 } 259 260 pmic->irq = gpio_to_irq(pmic->gpio); [ Edit. Actually I can see that the original author must have thought that this needed to be released but it doesn't. ] 261 262 hi6421_spmi_pmic_irq_prc(pmic); 263 264 pmic->irqs = devm_kzalloc(dev, HISI_IRQ_NUM * sizeof(int), GFP_KERNEL); 265 if (!pmic->irqs) { 266 ret = -ENOMEM; 267 goto irq_malloc; This is a goto with a ComeFrom style label name, which says where it is called from (The goto is at the place where irq_malloc fails). This is a useless label name because we can see from the line before that the alloc failed. What we want to know is what the goto does! 268 } 269 270 pmic->domain = irq_domain_add_simple(np, HISI_IRQ_NUM, 0, 271 &hi6421_spmi_domain_ops, pmic); 272 if (!pmic->domain) { 273 dev_err(dev, "failed irq domain add simple!\n"); 274 ret = -ENODEV; 275 goto irq_malloc; Here the label name is even more useless here because "irq_malloc" didn't fail on the line before. #Confusing But we still don't know what the goto does. If we scroll down then we see that "goto irq_malloc" releases the IRQ. A better name would be "goto err_irq;" 276 } 277 278 for (i = 0; i < HISI_IRQ_NUM; i++) { 279 virq = irq_create_mapping(pmic->domain, i); 280 if (!virq) { 281 dev_err(dev, "Failed mapping hwirq\n"); 282 ret = -ENOSPC; 283 goto irq_malloc; 284 } 285 pmic->irqs[i] = virq; 286 dev_dbg(dev, "%s: pmic->irqs[%d] = %d\n", 287 __func__, i, pmic->irqs[i]); 288 } 289 290 ret = request_threaded_irq(pmic->irq, hi6421_spmi_irq_handler, NULL, 291 IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND, 292 "pmic", pmic); Except it turns out that we don't actually request the IRQ until this line. So those earlier "goto err_irq;" things are bogus. 293 if (ret < 0) { 294 dev_err(dev, "could not claim pmic IRQ: error %d\n", ret); 295 goto irq_malloc; 296 } 297 298 dev_set_drvdata(&pdev->dev, pmic); 299 300 /* 301 * The logic below will rely that the pmic is already stored at 302 * drvdata. 303 */ 304 dev_dbg(&pdev->dev, "SPMI-PMIC: adding children for %pOF\n", 305 pdev->dev.of_node); 306 ret = devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, 307 hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs), 308 NULL, 0, NULL); 309 if (!ret) 310 return 0; This is "success handling" anti-pattern and "last condition is weird" anti-pattern. We should always do failure handling. The code should look like: success(); success(); success(); success(); if () { failure(); failure(); failure(); } success(); success(); if () { failure(); failure(); failure(); } Failure is indented twice and success once. 311 312 dev_err(dev, "Failed to add child devices: %d\n", ret); 313 314 irq_malloc: 315 free_irq(pmic->irq, pmic); This free should only be done if devm_mfd_add_devices() fails. I don't know what happens if you free an IRQ which has not been requested. I think it triggers a WARN(). 316 317 return ret; 318 } regards, dan carpenter From nami at 4sasa.xyz Wed Nov 18 17:22:00 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Thu, 19 Nov 2020 01:22:00 +0800 Subject: GREETINGS: Message-ID: <20201118172243.39F1A85F68@fraxinus.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Mary vantelli Email:maryvantelli at gmail.com From nami at 4sasa.xyz Wed Nov 18 17:22:00 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Thu, 19 Nov 2020 01:22:00 +0800 Subject: GREETINGS: Message-ID: <20201118172244.1A0AD204CC@silver.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Mary vantelli Email:maryvantelli at gmail.com From nami at 4sasa.xyz Wed Nov 18 17:38:29 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Thu, 19 Nov 2020 01:38:29 +0800 Subject: GREETINGS: Message-ID: <20201118173834.D45B4868C4@whitealder.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Mary vantelli Email:maryvantelli at gmail.com From jrdr.linux at gmail.com Wed Nov 18 19:36:14 2020 From: jrdr.linux at gmail.com (Souptick Joarder) Date: Thu, 19 Nov 2020 01:06:14 +0530 Subject: [PATCH v2] media: atomisp: Fixed error handling path In-Reply-To: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> References: <1604455331-28031-1-git-send-email-jrdr.linux@gmail.com> Message-ID: On Wed, Nov 4, 2020 at 7:32 AM Souptick Joarder wrote: > > Inside alloc_user_pages() based on flag value either pin_user_pages() > or get_user_pages_fast() will be called. However, these API might fail. > > But free_user_pages() called in error handling path doesn't bother > about return value and will try to unpin bo->pgnr pages, which is > incorrect. > > Fix this by passing the page_nr to free_user_pages(). If page_nr > 0 > pages will be unpinned based on bo->mem_type. This will also take care > of non error handling path. > > Fixes: 14a638ab96c5 ("media: atomisp: use pin_user_pages() for memory > allocation") > Signed-off-by: Souptick Joarder > Reviewed-by: Dan Carpenter > Cc: John Hubbard > Cc: Ira Weiny > Cc: Dan Carpenter > --- > v2: > Added review tag. Any further comment ? If no, can we get this patch in queue for 5.11 ? > > drivers/staging/media/atomisp/pci/hmm/hmm_bo.c | 13 ++++++++----- > 1 file changed, 8 insertions(+), 5 deletions(-) > > diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c > index f13af23..0168f98 100644 > --- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c > +++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c > @@ -857,16 +857,17 @@ static void free_private_pages(struct hmm_buffer_object *bo, > kfree(bo->page_obj); > } > > -static void free_user_pages(struct hmm_buffer_object *bo) > +static void free_user_pages(struct hmm_buffer_object *bo, > + unsigned int page_nr) > { > int i; > > hmm_mem_stat.usr_size -= bo->pgnr; > > if (bo->mem_type == HMM_BO_MEM_TYPE_PFN) { > - unpin_user_pages(bo->pages, bo->pgnr); > + unpin_user_pages(bo->pages, page_nr); > } else { > - for (i = 0; i < bo->pgnr; i++) > + for (i = 0; i < page_nr; i++) > put_page(bo->pages[i]); > } > kfree(bo->pages); > @@ -942,6 +943,8 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, > dev_err(atomisp_dev, > "get_user_pages err: bo->pgnr = %d, pgnr actually pinned = %d.\n", > bo->pgnr, page_nr); > + if (page_nr < 0) > + page_nr = 0; > goto out_of_mem; > } > > @@ -954,7 +957,7 @@ static int alloc_user_pages(struct hmm_buffer_object *bo, > > out_of_mem: > > - free_user_pages(bo); > + free_user_pages(bo, page_nr); > > return -ENOMEM; > } > @@ -1037,7 +1040,7 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo) > if (bo->type == HMM_BO_PRIVATE) > free_private_pages(bo, &dynamic_pool, &reserved_pool); > else if (bo->type == HMM_BO_USER) > - free_user_pages(bo); > + free_user_pages(bo, bo->pgnr); > else > dev_err(atomisp_dev, "invalid buffer type.\n"); > mutex_unlock(&bo->mutex); > -- > 1.9.1 > From vkoul at kernel.org Thu Nov 19 05:30:59 2020 From: vkoul at kernel.org (Vinod Koul) Date: Thu, 19 Nov 2020 11:00:59 +0530 Subject: [PATCH v4 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: <20201031122246.16497-3-sergio.paracuellos@gmail.com> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-3-sergio.paracuellos@gmail.com> Message-ID: <20201119053059.GY50232@vkoul-mobl> On 31-10-20, 13:22, Sergio Paracuellos wrote: > +#define RG_PE1_PIPE_REG 0x02c > +#define RG_PE1_PIPE_RST BIT(12) > +#define RG_PE1_PIPE_CMD_FRC BIT(4) > + > +#define RG_P0_TO_P1_WIDTH 0x100 > +#define RG_PE1_H_LCDDS_REG 0x49c > +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) > +#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) Pls use FIELD_{GET|PREP} instead of coding like this, you already defined the mask, use it to set and get the reg field ;) > + > +#define RG_PE1_FRC_H_XTAL_REG 0x400 > +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) > +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) > +#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) > + > +#define RG_PE1_FRC_PHY_REG 0x000 > +#define RG_PE1_FRC_PHY_EN BIT(4) > +#define RG_PE1_PHY_EN BIT(5) > + > +#define RG_PE1_H_PLL_REG 0x490 > +#define RG_PE1_H_PLL_BC GENMASK(23, 22) > +#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) > +#define RG_PE1_H_PLL_BP GENMASK(21, 18) > +#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) > +#define RG_PE1_H_PLL_IR GENMASK(15, 12) > +#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) > +#define RG_PE1_H_PLL_IC GENMASK(11, 8) > +#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) > +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) > +#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) > +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) > +#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) > + > +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc > +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) > +#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) > + > +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 > +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) > +#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) > + > +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 > +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) > +#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) > +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) > +#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) > + > +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 > +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) > + > +#define RG_PE1_H_PLL_BR_REG 0x4ac > +#define RG_PE1_H_PLL_BR GENMASK(18, 16) > +#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) > + > +#define RG_PE1_MSTCKDIV_REG 0x414 > +#define RG_PE1_MSTCKDIV GENMASK(7, 6) > +#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) > + > +#define RG_PE1_FRC_MSTCKDIV BIT(5) > + > +#define XTAL_MODE_SEL_SHIFT 6 Bonus you dont need to define shifts if you use stuff defined in bitfield.h > +struct mt7621_pci_phy { > + struct device *dev; > + struct regmap *regmap; > + struct phy *phy; > + void __iomem *port_base; > + bool has_dual_port; > + bool bypass_pipe_rst; > +}; > + > +static inline u32 phy_read(struct mt7621_pci_phy *phy, u32 reg) > +{ > + u32 val; > + > + regmap_read(phy->regmap, reg, &val); > + > + return val; > +} > + > +static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) > +{ > + regmap_write(phy->regmap, reg, val); Why not use regmap_ calls directly and avoid the dummy wrappers..? > +} > + > +static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, > + u32 reg, u32 clr, u32 set) > +{ > + u32 val = phy_read(phy, reg); > + > + val &= ~clr; > + val |= set; > + phy_write(phy, val, reg); why not use regmap_update_bits() instead > +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) > +{ > + struct device *dev = phy->dev; > + u32 xtal_mode; > + > + xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0) > + >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; > + > + /* Set PCIe Port PHY to disable SSC */ > + /* Debug Xtal Type */ > + mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, > + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, > + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00)); > + > + /* disable port */ > + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, > + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); > + > + if (phy->has_dual_port) { > + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, > + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); > + } > + > + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ > + /* Set Pre-divider ratio (for host mode) */ > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > + RG_PE1_H_PLL_PREDIV, > + RG_PE1_H_PLL_PREDIV_VAL(0x01)); > + dev_info(dev, "Xtal is 40MHz\n"); > + } else if (xtal_mode >= 6) { /* 25MHz Xal */ > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > + RG_PE1_H_PLL_PREDIV, > + RG_PE1_H_PLL_PREDIV_VAL(0x00)); > + /* Select feedback clock */ > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, > + RG_PE1_H_PLL_FBKSEL, > + RG_PE1_H_PLL_FBKSEL_VAL(0x01)); > + /* DDS NCPO PCW (for host mode) */ > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, > + RG_PE1_H_LCDDS_SSC_PRD, > + RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000)); > + /* DDS SSC dither period control */ > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, > + RG_PE1_H_LCDDS_SSC_PRD, > + RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d)); > + /* DDS SSC dither amplitude control */ > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, > + RG_PE1_H_LCDDS_SSC_DELTA | > + RG_PE1_H_LCDDS_SSC_DELTA1, > + RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) | > + RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a)); > + dev_info(dev, "Xtal is 25MHz\n"); Debug please > + } else { /* 20MHz Xtal */ > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > + RG_PE1_H_PLL_PREDIV, > + RG_PE1_H_PLL_PREDIV_VAL(0x00)); > + > + dev_info(dev, "Xtal is 20MHz\n"); ditto -- ~Vinod From sergio.paracuellos at gmail.com Thu Nov 19 06:05:22 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 07:05:22 +0100 Subject: [PATCH v4 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: <20201119053059.GY50232@vkoul-mobl> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-3-sergio.paracuellos@gmail.com> <20201119053059.GY50232@vkoul-mobl> Message-ID: Hi Vinod, Thanks for the review. On Thu, Nov 19, 2020 at 6:31 AM Vinod Koul wrote: > > On 31-10-20, 13:22, Sergio Paracuellos wrote: > > > +#define RG_PE1_PIPE_REG 0x02c > > +#define RG_PE1_PIPE_RST BIT(12) > > +#define RG_PE1_PIPE_CMD_FRC BIT(4) > > + > > +#define RG_P0_TO_P1_WIDTH 0x100 > > +#define RG_PE1_H_LCDDS_REG 0x49c > > +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) > > +#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) > > Pls use FIELD_{GET|PREP} instead of coding like this, you already > defined the mask, use it to set and get the reg field ;) Will change this and properly remove all of these *_VAL defines. > > > + > > +#define RG_PE1_FRC_H_XTAL_REG 0x400 > > +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) > > +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) > > +#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) > > + > > +#define RG_PE1_FRC_PHY_REG 0x000 > > +#define RG_PE1_FRC_PHY_EN BIT(4) > > +#define RG_PE1_PHY_EN BIT(5) > > + > > +#define RG_PE1_H_PLL_REG 0x490 > > +#define RG_PE1_H_PLL_BC GENMASK(23, 22) > > +#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) > > +#define RG_PE1_H_PLL_BP GENMASK(21, 18) > > +#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) > > +#define RG_PE1_H_PLL_IR GENMASK(15, 12) > > +#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) > > +#define RG_PE1_H_PLL_IC GENMASK(11, 8) > > +#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) > > +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) > > +#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) > > +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) > > +#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) > > + > > +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc > > +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) > > +#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) > > + > > +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 > > +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) > > +#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) > > + > > +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 > > +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) > > +#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) > > +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) > > +#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) > > + > > +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 > > +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) > > + > > +#define RG_PE1_H_PLL_BR_REG 0x4ac > > +#define RG_PE1_H_PLL_BR GENMASK(18, 16) > > +#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) > > + > > +#define RG_PE1_MSTCKDIV_REG 0x414 > > +#define RG_PE1_MSTCKDIV GENMASK(7, 6) > > +#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) > > + > > +#define RG_PE1_FRC_MSTCKDIV BIT(5) > > + > > +#define XTAL_MODE_SEL_SHIFT 6 > Bonus you dont need to define shifts if you use stuff defined in > bitfield.h I will also check how to remove this SHIFT. > > > +struct mt7621_pci_phy { > > + struct device *dev; > > + struct regmap *regmap; > > + struct phy *phy; > > + void __iomem *port_base; > > + bool has_dual_port; > > + bool bypass_pipe_rst; > > +}; > > + > > +static inline u32 phy_read(struct mt7621_pci_phy *phy, u32 reg) > > +{ > > + u32 val; > > + > > + regmap_read(phy->regmap, reg, &val); > > + > > + return val; > > +} > > + > > +static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) > > +{ > > + regmap_write(phy->regmap, reg, val); > > Why not use regmap_ calls directly and avoid the dummy wrappers..? This is because name was the dummy names are a bit shorter :) but if it is also necessary I will use directly regmap_ functions. > > > +} > > + > > +static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, > > + u32 reg, u32 clr, u32 set) > > +{ > > + u32 val = phy_read(phy, reg); > > + > > + val &= ~clr; > > + val |= set; > > + phy_write(phy, val, reg); > > why not use regmap_update_bits() instead True. Will change. > > > +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) > > +{ > > + struct device *dev = phy->dev; > > + u32 xtal_mode; > > + > > + xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0) > > + >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; > > + > > + /* Set PCIe Port PHY to disable SSC */ > > + /* Debug Xtal Type */ > > + mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, > > + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, > > + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00)); > > + > > + /* disable port */ > > + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, > > + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); > > + > > + if (phy->has_dual_port) { > > + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, > > + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); > > + } > > + > > + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ > > + /* Set Pre-divider ratio (for host mode) */ > > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > > + RG_PE1_H_PLL_PREDIV, > > + RG_PE1_H_PLL_PREDIV_VAL(0x01)); > > + dev_info(dev, "Xtal is 40MHz\n"); > > + } else if (xtal_mode >= 6) { /* 25MHz Xal */ > > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > > + RG_PE1_H_PLL_PREDIV, > > + RG_PE1_H_PLL_PREDIV_VAL(0x00)); > > + /* Select feedback clock */ > > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, > > + RG_PE1_H_PLL_FBKSEL, > > + RG_PE1_H_PLL_FBKSEL_VAL(0x01)); > > + /* DDS NCPO PCW (for host mode) */ > > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, > > + RG_PE1_H_LCDDS_SSC_PRD, > > + RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000)); > > + /* DDS SSC dither period control */ > > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, > > + RG_PE1_H_LCDDS_SSC_PRD, > > + RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d)); > > + /* DDS SSC dither amplitude control */ > > + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, > > + RG_PE1_H_LCDDS_SSC_DELTA | > > + RG_PE1_H_LCDDS_SSC_DELTA1, > > + RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) | > > + RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a)); > > + dev_info(dev, "Xtal is 25MHz\n"); > > Debug please Will change this trace to debug. > > > + } else { /* 20MHz Xtal */ > > + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, > > + RG_PE1_H_PLL_PREDIV, > > + RG_PE1_H_PLL_PREDIV_VAL(0x00)); > > + > > + dev_info(dev, "Xtal is 20MHz\n"); > > ditto And this one too. > -- > ~Vinod Again, thanks for the review. Will change this and send v5 with this changes and collect ack's and reviewed's from this series. Best regards, Sergio Paracuellos From hch at lst.de Thu Nov 19 07:59:59 2020 From: hch at lst.de (Christoph Hellwig) Date: Thu, 19 Nov 2020 08:59:59 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201109094303.llqsxqoxjagiqa55@gilmour.lan> References: <20201106151411.321743-1-maxime@cerno.tech> <20201106160737.GA31913@lst.de> <20201109094303.llqsxqoxjagiqa55@gilmour.lan> Message-ID: <20201119075959.GA15942@lst.de> On Mon, Nov 09, 2020 at 10:43:03AM +0100, Maxime Ripard wrote: > Hi Christoph, Chen-Yu, Hans, > > On Fri, Nov 06, 2020 at 05:07:37PM +0100, Christoph Hellwig wrote: > > Thanks, > > > > this looks good to me: > > > > Reviewed-by: Christoph Hellwig > > > > Can you include this patch at the end of your series to that it gets > > picked up with the other patches? > > I guess the easiest to avoid bisection issues would be to merge all this > through drm-misc, would that work for you? Is this going to get picked up in drm-misc? I don't see it in linux-next so far. From maxime at cerno.tech Thu Nov 19 08:42:15 2020 From: maxime at cerno.tech (Maxime Ripard) Date: Thu, 19 Nov 2020 09:42:15 +0100 Subject: [PATCH 0/7] sunxi: Remove the calls to dma_direct_set_offset In-Reply-To: <20201119075959.GA15942@lst.de> References: <20201106151411.321743-1-maxime@cerno.tech> <20201106160737.GA31913@lst.de> <20201109094303.llqsxqoxjagiqa55@gilmour.lan> <20201119075959.GA15942@lst.de> Message-ID: <20201119084215.pnzypitnyfgxsgrg@gilmour.lan> Hi Christoph, On Thu, Nov 19, 2020 at 08:59:59AM +0100, Christoph Hellwig wrote: > On Mon, Nov 09, 2020 at 10:43:03AM +0100, Maxime Ripard wrote: > > Hi Christoph, Chen-Yu, Hans, > > > > On Fri, Nov 06, 2020 at 05:07:37PM +0100, Christoph Hellwig wrote: > > > Thanks, > > > > > > this looks good to me: > > > > > > Reviewed-by: Christoph Hellwig > > > > > > Can you include this patch at the end of your series to that it gets > > > picked up with the other patches? > > > > I guess the easiest to avoid bisection issues would be to merge all this > > through drm-misc, would that work for you? > > Is this going to get picked up in drm-misc? I don't see it in linux-next > so far. After some discussion with Arnd and Daniel, this will go through arm-soc, and I sent the PR here: https://lore.kernel.org/linux-arm-kernel/20201118091303.wa5npxyop3cdsczb at gilmour.lan/ It hasn't been merged yet though Maxime -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: From davidgow at google.com Thu Nov 19 08:29:03 2020 From: davidgow at google.com (David Gow) Date: Thu, 19 Nov 2020 00:29:03 -0800 Subject: [PATCH] staging: hikey9xx: Specify HAS_IOMEM dependency for MFD_HI6421_SPMI Message-ID: <20201119082903.3601758-1-davidgow@google.com> MFD_CORE is selected by MFD_HI6421_SPMI, and MFD_CORE depends on HAS_IOMEM. If HAS_IOMEM is not set, this can cause a conflict in Kconfig resolution, yielding the following error: WARNING: unmet direct dependencies detected for MFD_CORE Depends on [n]: HAS_IOMEM [=n] Selected by [y]: - MFD_HI6421_SPMI [=y] && STAGING [=y] && OF [=y] && SPMI [=y] By specifying HAS_IOMEM as a dependency for MFD_HI6421_SPMI (as SPMI_HISI3670 already dows), this issue is resolved, and no such warning appears when building on architectures without HAS_IOMEM. Signed-off-by: David Gow --- drivers/staging/hikey9xx/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/hikey9xx/Kconfig b/drivers/staging/hikey9xx/Kconfig index b29f5d5df134..2e48ded92a7e 100644 --- a/drivers/staging/hikey9xx/Kconfig +++ b/drivers/staging/hikey9xx/Kconfig @@ -25,6 +25,7 @@ config SPMI_HISI3670 # to be placed at drivers/mfd config MFD_HI6421_SPMI tristate "HiSilicon Hi6421v600 SPMI PMU/Codec IC" + depends on HAS_IOMEM depends on OF depends on SPMI select MFD_CORE -- 2.29.2.454.gaff20da3a2-goog From jmsbfrn at ownmail.net Thu Nov 19 15:57:46 2020 From: jmsbfrn at ownmail.net (HSBC London Office) Date: Thu, 19 Nov 2020 07:57:46 -0800 Subject: (BANK ALERT) About Your Fund// Message-ID: HSBC BANK PLC LONDON.(REGISTERED NO.1026167). ADDRESS: 8 CANADA SQUARE, CANARY WHARF, LONDON E14 5HQ, UK. Attn: Beneficiary, We write to inform you that Series of meetings have been held with the Secretary General of United Nations,U.S Department of State, the meeting ended this week. During the meeting we discovered that you have not receive your long overdue part payment of US$21.5M due to past corrupt Government Officials who almost held the funds to themselves for their selfish reason and some individuals who have taken advantage in an attempt to defraud you, which has led to unnecessary delay in releasing the funds to you. The United Nations/ U.S. Department of State have successfully passed a payment mandate to our bank, to clear all over due Contract funds, Lottery winnings, Inheritance/Investment funds owed to you and other individuals/organizations who have been found not to have receive their long overdue payment. A woman by name (MRS: CINDY MAY A CITIZEN OF USA) submit an application to our bank stating that you gave her the power of attorney to be the beneficiary of your Outstanding fund. She made us to believe that you are dead and that she is your next of kin. We decided to send you email through this address hoping to find out if you are dead or alive and also to find out if you at any time gave her the power of attorney to represent you, we decided to contact you before we can take any action because of the sensitivity nature of the transaction and the amount of money that is involved: For immediate release of your $21.5M to you legally as the legal recipient if you are alive and did not authorize her at any time, you are required to reconfirm YOUR FULL NAME, CURRENT ADDRESS AND DIRECT CELL PHONE NUMBER for onward proceeding on how you are going to receive the said funds legally without any problem either now or in future. Treat as urgent. Yours Sincerely, Mr. Noel Quinn HSBC Chief Executive Officer . From jmsbfrn at ownmail.net Thu Nov 19 16:04:13 2020 From: jmsbfrn at ownmail.net (HSBC London Office) Date: Thu, 19 Nov 2020 08:04:13 -0800 Subject: (BANK ALERT) About Your Fund// Message-ID: <02.AC.07884.FF436BF5@tf-vmsmta-p002.xpedite.com> HSBC BANK PLC LONDON.(REGISTERED NO.1026167). ADDRESS: 8 CANADA SQUARE, CANARY WHARF, LONDON E14 5HQ, UK. Attn: Beneficiary, We write to inform you that Series of meetings have been held with the Secretary General of United Nations,U.S Department of State, the meeting ended this week. During the meeting we discovered that you have not receive your long overdue part payment of US$21.5M due to past corrupt Government Officials who almost held the funds to themselves for their selfish reason and some individuals who have taken advantage in an attempt to defraud you, which has led to unnecessary delay in releasing the funds to you. The United Nations/ U.S. Department of State have successfully passed a payment mandate to our bank, to clear all over due Contract funds, Lottery winnings, Inheritance/Investment funds owed to you and other individuals/organizations who have been found not to have receive their long overdue payment. A woman by name (MRS: CINDY MAY A CITIZEN OF USA) submit an application to our bank stating that you gave her the power of attorney to be the beneficiary of your Outstanding fund. She made us to believe that you are dead and that she is your next of kin. We decided to send you email through this address hoping to find out if you are dead or alive and also to find out if you at any time gave her the power of attorney to represent you, we decided to contact you before we can take any action because of the sensitivity nature of the transaction and the amount of money that is involved: For immediate release of your $21.5M to you legally as the legal recipient if you are alive and did not authorize her at any time, you are required to reconfirm YOUR FULL NAME, CURRENT ADDRESS AND DIRECT CELL PHONE NUMBER for onward proceeding on how you are going to receive the said funds legally without any problem either now or in future. Treat as urgent. Yours Sincerely, Mr. Noel Quinn HSBC Chief Executive Officer . From gch981213 at gmail.com Thu Nov 19 09:32:16 2020 From: gch981213 at gmail.com (Chuanhong Guo) Date: Thu, 19 Nov 2020 17:32:16 +0800 Subject: [PATCH v3 3/5] clk: ralink: add clock driver for mt7621 SoC In-Reply-To: <20201113154632.24973-4-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-4-sergio.paracuellos@gmail.com> Message-ID: Hi! On Fri, Nov 13, 2020 at 11:46 PM Sergio Paracuellos wrote: > [...] > diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile > new file mode 100644 > index 000000000000..cf6f9216379d > --- /dev/null > +++ b/drivers/clk/ralink/Makefile Why ralink? The clock design of mt7621 doesn't seem to be part of ralink legacy stuff, and ralink is already acquired by mediatek anyway. I think it should be put in drivers/clk/mediatek instead. -- Regards, Chuanhong Guo From sergio.paracuellos at gmail.com Thu Nov 19 09:35:38 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 10:35:38 +0100 Subject: [PATCH v3 3/5] clk: ralink: add clock driver for mt7621 SoC In-Reply-To: References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-4-sergio.paracuellos@gmail.com> Message-ID: Hi, On Thu, Nov 19, 2020 at 10:32 AM Chuanhong Guo wrote: > > Hi! > > On Fri, Nov 13, 2020 at 11:46 PM Sergio Paracuellos > wrote: > > [...] > > diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile > > new file mode 100644 > > index 000000000000..cf6f9216379d > > --- /dev/null > > +++ b/drivers/clk/ralink/Makefile > > Why ralink? The clock design of mt7621 doesn't seem > to be part of ralink legacy stuff, and ralink is already > acquired by mediatek anyway. > I think it should be put in drivers/clk/mediatek instead. I don't really know. It seems in that directory only arm arch related code from mediatek is included... but let's see what other people think about this. > > -- > Regards, > Chuanhong Guo Best regards, Sergio Paracuellos From juant.aldea at gmail.com Thu Nov 19 11:40:30 2020 From: juant.aldea at gmail.com (Juan Antonio Aldea-Armenteros) Date: Thu, 19 Nov 2020 12:40:30 +0100 Subject: [PATCH v1] staging: trivial: hikey9xx: fix be32<->u32 casting warnings Message-ID: <20201119114029.183828-1-juant.aldea@gmail.com> This patch fixes the following warnings reported by sparse by adding missing __force annotations. drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:239:25: warning: cast from restricted __be32 Rationale for #164: data is declared as u32, and it read then converted by means of be32_to_cpu(). Said function expects a __be32 but data is u32, therefore there's a type missmatch here. Rationale for #293: Is the dualof #164. This time data going to be written so it needs to be converted from cpu to be32, but writel() expects u32 and the output of cpu_to_be32 returns a __be32. Signed-off-by: Juan Antonio Aldea-Armenteros --- drivers/staging/hikey9xx/hisi-spmi-controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c index f831c43f4783..861aedd5de48 100644 --- a/drivers/staging/hikey9xx/hisi-spmi-controller.c +++ b/drivers/staging/hikey9xx/hisi-spmi-controller.c @@ -161,7 +161,7 @@ static int spmi_read_cmd(struct spmi_controller *ctrl, SPMI_SLAVE_OFFSET * slave_id + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i * SPMI_PER_DATAREG_BYTE); - data = be32_to_cpu((__be32)data); + data = be32_to_cpu((__be32 __force)data); if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { memcpy(buf, &data, sizeof(data)); buf += sizeof(data); @@ -236,7 +236,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, buf += (bc % SPMI_PER_DATAREG_BYTE); } - writel((u32)cpu_to_be32(data), + writel((u32 __force)cpu_to_be32(data), spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR + SPMI_PER_DATAREG_BYTE * i); -- 2.28.0 From juant.aldea at gmail.com Thu Nov 19 12:27:38 2020 From: juant.aldea at gmail.com (Juan Antonio Aldea-Armenteros) Date: Thu, 19 Nov 2020 13:27:38 +0100 Subject: [PATCH v2] staging: trivial: hikey9xx: fix be32<->u32 casting warnings In-Reply-To: <20201119114029.183828-1-juant.aldea@gmail.com> References: <20201119114029.183828-1-juant.aldea@gmail.com> Message-ID: <20201119122737.189675-1-juant.aldea@gmail.com> This patch fixes the following warnings reported by sparse, by adding missing __force annotations. drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 drivers/staging/hikey9xx/hisi-spmi-controller.c:239:25: warning: cast from restricted __be32 Rationale for #164: data is declared as u32, and it is read and then converted by means of be32_to_cpu(). Said function expects a __be32 but data is u32, therefore there's a type missmatch here. Rationale for #239: Is the dual of #164. This time data going to be written so it needs to be converted from cpu to __be32, but writel() expects u32 and the output of cpu_to_be32 returns a __be32. Signed-off-by: Juan Antonio Aldea-Armenteros --- Changes in V2: - Fix typo in commit message. drivers/staging/hikey9xx/hisi-spmi-controller.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/hikey9xx/hisi-spmi-controller.c b/drivers/staging/hikey9xx/hisi-spmi-controller.c index f831c43f4783..861aedd5de48 100644 --- a/drivers/staging/hikey9xx/hisi-spmi-controller.c +++ b/drivers/staging/hikey9xx/hisi-spmi-controller.c @@ -161,7 +161,7 @@ static int spmi_read_cmd(struct spmi_controller *ctrl, SPMI_SLAVE_OFFSET * slave_id + SPMI_APB_SPMI_RDATA0_BASE_ADDR + i * SPMI_PER_DATAREG_BYTE); - data = be32_to_cpu((__be32)data); + data = be32_to_cpu((__be32 __force)data); if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { memcpy(buf, &data, sizeof(data)); buf += sizeof(data); @@ -236,7 +236,7 @@ static int spmi_write_cmd(struct spmi_controller *ctrl, buf += (bc % SPMI_PER_DATAREG_BYTE); } - writel((u32)cpu_to_be32(data), + writel((u32 __force)cpu_to_be32(data), spmi_controller->base + chnl_ofst + SPMI_APB_SPMI_WDATA0_BASE_ADDR + SPMI_PER_DATAREG_BYTE * i); -- 2.28.0 From digetx at gmail.com Thu Nov 19 14:22:43 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Thu, 19 Nov 2020 17:22:43 +0300 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <20201116133311.GB4739@sirena.org.uk> References: <20201112171600.GD4742@sirena.org.uk> <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> <20201113172859.GF4828@sirena.org.uk> <74cfc6a9-3f59-d679-14b7-51102a6f11b3@gmail.com> <20201116133311.GB4739@sirena.org.uk> Message-ID: <332ab946-daee-bb83-24ab-0bda4fd8e1ef@gmail.com> 16.11.2020 16:33, Mark Brown ?????: > On Sun, Nov 15, 2020 at 08:42:10PM +0300, Dmitry Osipenko wrote: >> 13.11.2020 20:28, Mark Brown ?????: > >>>> What should we do? > >>> As I keep saying the consumer driver should be enumerating the voltages >>> it can set, if it can't find any and wants to continue then it can just >>> skip setting voltages later on. If only some are unavailable then it >>> probably wants to eliminate those specific OPPs instead. > >> I'm seeing a dummy regulator as a helper for consumer drivers which >> removes burden of handling an absent (optional) regulator. Is this a >> correct understanding of a dummy regulator? > >> Older DTBs don't have a regulator and we want to keep them working. This >> is equal to a physically absent regulator and in this case it's an >> optional regulator, IMO. > > No, you are failing to understand the purpose of this code. To > reiterate unless the device supports operating with the supply > physically absent then the driver should not be attempting to use > regulator_get_optional(). That exists specifically for the case where > the supply may be absent, nothing else. The dummy regulator is there > precisely for the case where the system does not describe supplies that > we know are required for the device to function, it fixes up that > omission so we don't need to open code handling of this in every single > consumer driver. The original intention of regulator_get_optional() is clear to me, but nothing really stops drivers from slightly re-purposing this API, IMO. Drivers should be free to assume that if regulator isn't defined by firmware, then it's physically absent if this doesn't break anything. Of course in some cases it's unsafe to make such assumptions. I think it's a bit unpractical to artificially limit API usage without a good reason, i.e. if nothing breaks underneath of a driver. > Regulators that are present but not described by the firmware are a > clearly different case to regulators that are not physically there, > hardware with actually optional regulators will generally require some > configuration for this case. > I have good news. After spending some more time on trying out different things, I found that my previous assumption about the fixed-regulator was wrong, it actually accepts voltage changes, i.e. regulator consumer doesn't get a error on a voltage-change. This is exactly what is needed for the OPP core to work properly. This means that there is no need to add special quirks to work around absent regulators, we will just add a fixed regulator to the DTs which don't specify a real regulator. The OPP core will perform voltage checking and filter out unsupported OPPs. The older DTBs will continue to work as well. From broonie at kernel.org Thu Nov 19 15:19:18 2020 From: broonie at kernel.org (Mark Brown) Date: Thu, 19 Nov 2020 15:19:18 +0000 Subject: [PATCH v1 11/30] drm/tegra: dc: Support OPP and SoC core voltage scaling In-Reply-To: <332ab946-daee-bb83-24ab-0bda4fd8e1ef@gmail.com> References: <20201112200123.GF4742@sirena.org.uk> <20201113142937.GB4828@sirena.org.uk> <7f066805-97d9-088f-e89d-a554fe478574@gmail.com> <20201113161550.GC4828@sirena.org.uk> <3beaa12b-4a50-a3b6-fc43-ebb5ce7a8db7@gmail.com> <20201113172859.GF4828@sirena.org.uk> <74cfc6a9-3f59-d679-14b7-51102a6f11b3@gmail.com> <20201116133311.GB4739@sirena.org.uk> <332ab946-daee-bb83-24ab-0bda4fd8e1ef@gmail.com> Message-ID: <20201119151918.GA5554@sirena.org.uk> On Thu, Nov 19, 2020 at 05:22:43PM +0300, Dmitry Osipenko wrote: > 16.11.2020 16:33, Mark Brown ?????: > > No, you are failing to understand the purpose of this code. To > > reiterate unless the device supports operating with the supply > > physically absent then the driver should not be attempting to use > > regulator_get_optional(). That exists specifically for the case where > The original intention of regulator_get_optional() is clear to me, but > nothing really stops drivers from slightly re-purposing this API, IMO. > Drivers should be free to assume that if regulator isn't defined by > firmware, then it's physically absent if this doesn't break anything. Of > course in some cases it's unsafe to make such assumptions. I think it's > a bit unpractical to artificially limit API usage without a good reason, > i.e. if nothing breaks underneath of a driver. If the supply can be physically absent without breaking anything then this is the intended use case for optional regulators. This is a *very* uncommon. > > Regulators that are present but not described by the firmware are a > > clearly different case to regulators that are not physically there, > > hardware with actually optional regulators will generally require some > > configuration for this case. > I have good news. After spending some more time on trying out different > things, I found that my previous assumption about the fixed-regulator > was wrong, it actually accepts voltage changes, i.e. regulator consumer > doesn't get a error on a voltage-change. This is exactly what is needed > for the OPP core to work properly. To be clear when you set a voltage range you will get the minimum voltage that can be supported within that range on the system given all the other constraints the system has. For fixed voltage regulators or regulators constraints to not change voltage this means that if whatever voltage they are fixed at is in the range requested then the API will report success. -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: not available URL: From sergio.paracuellos at gmail.com Thu Nov 19 15:43:33 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 16:43:33 +0100 Subject: [PATCH v5 0/4] MT7621 PCIe PHY Message-ID: <20201119154337.9195-1-sergio.paracuellos@gmail.com> This series adds support for the PCIe PHY found in the Mediatek MT7621 SoC. There is also a 'mt7621-pci' driver which is the controller part which is still in staging and is a client of this phy. Both drivers have been tested together in a gnubee1 board. This series are rebased on the top of linux-next: commit 4e78c578cb98 ("Add linux-next specific files for 20201030") Changes in v5: - PATCH 1/4: Recollect Rob's Reviewed-by of bindings. - PATCH 4/4: Recollect Greg's Acked-by for removing stuff from staging area. - Make Vinod's review comments changes in [0]: * Use FIELD_GET and FIELD_PREP apis and avoid multiple *_VAL and *_SHIFT custom definitions. * Remove phy-read and phy-write internal functions and directly call regmap_read and regmap_write in 'mt7621_phy_rmw'. * Change some traces from info to debug log level. * Note that I have maintained 'mt7621_phy_rmw' instead of use 'regmap_update_bits'. This is because in order to get a reliable boot registers must be written event the contained value in that register is the same. I have preferred doing in this way instead of using 'regmap_update_bits_base' passing 'false' for async and 'true' for the force write. If this way of using 'regmap_update_bits_base' is preferred just let me know. Changes in v4: - Bindings moved from txt to yaml so previous Rob's Reviewed-by is not in the new patch with the yaml file. - 'phy-cells' property means now if phy is dual-ported. - Avoid custom 'xlate' function and properly set registers when the phy is dual ported. - Add use of 'builtin_platform_driver'. - Added a patch including myself as maintainer in the MAINTAINERS file. - Add a patch removing patch from staging to make easier the complete inclusion and avoid possible problems might appear in 'linux-next' if the series are included. Changes in v3: - Recollect Rob's Reviewed-by of bindings. - Make Kishon Vijay suggested changes in v2: (See https://lkml.org/lkml/2019/4/17/53) - Kconfig: * Add depends on COMPILE_TEST * Select REGMAP_MMIO - Make use of 'soc_device_attribute' and 'soc_device_match' - Use regmap mmio API instead of directly 'readl' and 'writel'. - Use 'platform_get_resource' instead of 'of_address_to_resource'. Changes in v2: - Reorder patches to get bindings first in the series. - Don't use child nodes in the device tree. Use #phy-cells=1 instead. - Update driver code with new 'xlate' function for the new device tree. - Minor changes in driver's macros changing some spaces to tabs. Thanks in advance for your time. Best regards, Sergio Paracuellos [0]: http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2020-November/148864.html Sergio Paracuellos (4): dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY phy: ralink: Add PHY driver for MT7621 PCIe PHY MAINTAINERS: add MT7621 PHY PCI maintainer staging: mt7621-pci-phy: remove driver from staging .../phy}/mediatek,mt7621-pci-phy.yaml | 0 MAINTAINERS | 6 + drivers/phy/ralink/Kconfig | 8 ++ drivers/phy/ralink/Makefile | 1 + .../ralink/phy-mt7621-pci.c} | 103 +++++++----------- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/mt7621-pci-phy/Kconfig | 8 -- drivers/staging/mt7621-pci-phy/Makefile | 2 - drivers/staging/mt7621-pci-phy/TODO | 4 - 10 files changed, 53 insertions(+), 82 deletions(-) rename {drivers/staging/mt7621-pci-phy => Documentation/devicetree/bindings/phy}/mediatek,mt7621-pci-phy.yaml (100%) rename drivers/{staging/mt7621-pci-phy/pci-mt7621-phy.c => phy/ralink/phy-mt7621-pci.c} (76%) delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile delete mode 100644 drivers/staging/mt7621-pci-phy/TODO -- 2.25.1 From sergio.paracuellos at gmail.com Thu Nov 19 15:43:34 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 16:43:34 +0100 Subject: [PATCH v5 1/4] dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY In-Reply-To: <20201119154337.9195-1-sergio.paracuellos@gmail.com> References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: <20201119154337.9195-2-sergio.paracuellos@gmail.com> Add bindings to describe Mediatek MT7621 PCIe PHY. Signed-off-by: Sergio Paracuellos Reviewed-by: Rob Herring --- .../bindings/phy/mediatek,mt7621-pci-phy.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml new file mode 100644 index 000000000000..cf32bbc45b5d --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek Mt7621 PCIe PHY Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +properties: + compatible: + const: mediatek,mt7621-pci-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 1 + description: selects if the phy is dual-ported + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + pcie0_phy: pcie-phy at 1e149000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1e149000 0x0700>; + #phy-cells = <1>; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Thu Nov 19 15:43:35 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 16:43:35 +0100 Subject: [PATCH v5 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: <20201119154337.9195-1-sergio.paracuellos@gmail.com> References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: <20201119154337.9195-3-sergio.paracuellos@gmail.com> This patch adds a driver for the PCIe PHY of MT7621 SoC. Signed-off-by: Sergio Paracuellos --- drivers/phy/ralink/Kconfig | 8 + drivers/phy/ralink/Makefile | 1 + drivers/phy/ralink/phy-mt7621-pci.c | 346 ++++++++++++++++++++++++++++ 3 files changed, 355 insertions(+) create mode 100644 drivers/phy/ralink/phy-mt7621-pci.c diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig index da982c9cffb3..2fabb14d2998 100644 --- a/drivers/phy/ralink/Kconfig +++ b/drivers/phy/ralink/Kconfig @@ -2,6 +2,14 @@ # # PHY drivers for Ralink platforms. # +config PHY_MT7621_PCI + tristate "MediaTek MT7621 PCI PHY Driver" + depends on (RALINK || COMPILE_TEST) && OF + select GENERIC_PHY + select REGMAP_MMIO + help + Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, + config PHY_RALINK_USB tristate "Ralink USB PHY driver" depends on RALINK || COMPILE_TEST diff --git a/drivers/phy/ralink/Makefile b/drivers/phy/ralink/Makefile index d8d3ffcf0a15..cda2a4a7ca5e 100644 --- a/drivers/phy/ralink/Makefile +++ b/drivers/phy/ralink/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_MT7621_PCI) += phy-mt7621-pci.o obj-$(CONFIG_PHY_RALINK_USB) += phy-ralink-usb.o diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c new file mode 100644 index 000000000000..c452bc679d53 --- /dev/null +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mediatek MT7621 PCI PHY Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RG_PE1_PIPE_REG 0x02c +#define RG_PE1_PIPE_RST BIT(12) +#define RG_PE1_PIPE_CMD_FRC BIT(4) + +#define RG_P0_TO_P1_WIDTH 0x100 +#define RG_PE1_H_LCDDS_REG 0x49c +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) + +#define RG_PE1_FRC_H_XTAL_REG 0x400 +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) + +#define RG_PE1_FRC_PHY_REG 0x000 +#define RG_PE1_FRC_PHY_EN BIT(4) +#define RG_PE1_PHY_EN BIT(5) + +#define RG_PE1_H_PLL_REG 0x490 +#define RG_PE1_H_PLL_BC GENMASK(23, 22) +#define RG_PE1_H_PLL_BP GENMASK(21, 18) +#define RG_PE1_H_PLL_IR GENMASK(15, 12) +#define RG_PE1_H_PLL_IC GENMASK(11, 8) +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) + +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) + +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) + +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) + +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) + +#define RG_PE1_H_PLL_BR_REG 0x4ac +#define RG_PE1_H_PLL_BR GENMASK(18, 16) + +#define RG_PE1_MSTCKDIV_REG 0x414 +#define RG_PE1_MSTCKDIV GENMASK(7, 6) + +#define RG_PE1_FRC_MSTCKDIV BIT(5) + +#define XTAL_MODE_SEL_MASK 0x7 + +#define MAX_PHYS 2 + +/** + * struct mt7621_pci_phy - Mt7621 Pcie PHY core + * @dev: pointer to device + * @regmap: kernel regmap pointer + * @phy: pointer to the kernel PHY device + * @port_base: base register + * @has_dual_port: if the phy has dual ports. + * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst' + * needs to be executed. Depends on chip revision. + */ +struct mt7621_pci_phy { + struct device *dev; + struct regmap *regmap; + struct phy *phy; + void __iomem *port_base; + bool has_dual_port; + bool bypass_pipe_rst; +}; + +static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, + u32 reg, u32 clr, u32 set) +{ + u32 val; + + regmap_read(phy->regmap, reg, &val); + + val &= ~clr; + val |= set; + regmap_write(phy->regmap, reg, val); +} + +static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy) +{ + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_CMD_FRC); + } +} + +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) +{ + struct device *dev = phy->dev; + u32 xtal_mode; + + xtal_mode = FIELD_GET(XTAL_MODE_SEL_MASK, + rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0)); + + /* Set PCIe Port PHY to disable SSC */ + /* Debug Xtal Type */ + mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, + FIELD_PREP(RG_PE1_FRC_H_XTAL_TYPE, 0x00)); + + /* disable port */ + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, RG_PE1_PHY_EN, + RG_PE1_FRC_PHY_EN); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* Set Pre-divider ratio (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x01)); + + dev_dbg(dev, "Xtal is 40MHz\n"); + } else if (xtal_mode >= 6) { /* 25MHz Xal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + /* Select feedback clock */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, + RG_PE1_H_PLL_FBKSEL, + FIELD_PREP(RG_PE1_H_PLL_FBKSEL, 0x01)); + + /* DDS NCPO PCW (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x00)); + + /* DDS SSC dither period control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x18d)); + + /* DDS SSC dither amplitude control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, + RG_PE1_H_LCDDS_SSC_DELTA | + RG_PE1_H_LCDDS_SSC_DELTA1, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA, 0x4a) | + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA1, 0x4a)); + + dev_dbg(dev, "Xtal is 25MHz\n"); + } else { /* 20MHz Xtal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + dev_dbg(dev, "Xtal is 20MHz\n"); + } + + /* DDS clock inversion */ + mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG, + RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV); + + /* Set PLL bits */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, + RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | + RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN, + FIELD_PREP(RG_PE1_H_PLL_BC, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_BP, 0x06) | + FIELD_PREP(RG_PE1_H_PLL_IR, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_IC, 0x01) | + FIELD_PREP(RG_PE1_PLL_DIVEN, 0x02)); + + mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, + RG_PE1_H_PLL_BR, FIELD_PREP(RG_PE1_H_PLL_BR, 0x00)); + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* set force mode enable of da_pe1_mstckdiv */ + mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG, + RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV, + FIELD_PREP(RG_PE1_MSTCKDIV, 0x01) | + RG_PE1_FRC_MSTCKDIV); + } +} + +static int mt7621_pci_phy_init(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + if (mphy->bypass_pipe_rst) + mt7621_bypass_pipe_rst(mphy); + + mt7621_set_phy_for_ssc(mphy); + + return 0; +} + +static int mt7621_pci_phy_power_on(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Enable PHY and disable force mode */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_power_off(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Disable PHY */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_exit(struct phy *phy) +{ + return 0; +} + +static const struct phy_ops mt7621_pci_phy_ops = { + .init = mt7621_pci_phy_init, + .exit = mt7621_pci_phy_exit, + .power_on = mt7621_pci_phy_power_on, + .power_off = mt7621_pci_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); + + if (WARN_ON(args->args[0] >= MAX_PHYS)) + return ERR_PTR(-ENODEV); + + mt7621_phy->has_dual_port = args->args[0]; + + dev_info(dev, "PHY for 0x%08x (dual port = %d)\n", + (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port); + + return mt7621_phy->phy; +} + +static const struct soc_device_attribute mt7621_pci_quirks_match[] = { + { .soc_id = "mt7621", .revision = "E2" } +}; + +static const struct regmap_config mt7621_pci_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x700, +}; + +static int mt7621_pci_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct soc_device_attribute *attr; + struct phy_provider *provider; + struct mt7621_pci_phy *phy; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + attr = soc_device_match(mt7621_pci_quirks_match); + if (attr) + phy->bypass_pipe_rst = true; + + phy->dev = dev; + platform_set_drvdata(pdev, phy); + + phy->port_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->port_base)) { + dev_err(dev, "failed to remap phy regs\n"); + return PTR_ERR(phy->port_base); + } + + phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base, + &mt7621_pci_phy_regmap_config); + if (IS_ERR(phy->regmap)) + return PTR_ERR(phy->regmap); + + phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy->phy, phy); + + provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id mt7621_pci_phy_ids[] = { + { .compatible = "mediatek,mt7621-pci-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); + +static struct platform_driver mt7621_pci_phy_driver = { + .probe = mt7621_pci_phy_probe, + .driver = { + .name = "mt7621-pci-phy", + .of_match_table = of_match_ptr(mt7621_pci_phy_ids), + }, +}; + +builtin_platform_driver(mt7621_pci_phy_driver); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Thu Nov 19 15:43:36 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 16:43:36 +0100 Subject: [PATCH v5 3/4] MAINTAINERS: add MT7621 PHY PCI maintainer In-Reply-To: <20201119154337.9195-1-sergio.paracuellos@gmail.com> References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: <20201119154337.9195-4-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 pci phy driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aefbbecfb266..31f808e58e73 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11100,6 +11100,12 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/i2c-mt7621.txt F: drivers/i2c/busses/i2c-mt7621.c +MEDIATEK MT7621 PHY PCI DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml +F: drivers/phy/ralink/phy-mt7621-pci.c + MEDIATEK NAND CONTROLLER DRIVER L: linux-mtd at lists.infradead.org S: Orphan -- 2.25.1 From sergio.paracuellos at gmail.com Thu Nov 19 15:43:37 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Thu, 19 Nov 2020 16:43:37 +0100 Subject: [PATCH v5 4/4] staging: mt7621-pci-phy: remove driver from staging In-Reply-To: <20201119154337.9195-1-sergio.paracuellos@gmail.com> References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: <20201119154337.9195-5-sergio.paracuellos@gmail.com> Remove this driver from staging because it has been moved into its properly place in the kernel. Signed-off-by: Sergio Paracuellos Acked-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/mt7621-pci-phy/Kconfig | 8 - drivers/staging/mt7621-pci-phy/Makefile | 2 - drivers/staging/mt7621-pci-phy/TODO | 4 - .../mediatek,mt7621-pci-phy.yaml | 36 -- .../staging/mt7621-pci-phy/pci-mt7621-phy.c | 373 ------------------ 7 files changed, 426 deletions(-) delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile delete mode 100644 drivers/staging/mt7621-pci-phy/TODO delete mode 100644 drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml delete mode 100644 drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2d0310448eba..8a03ba56def5 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -94,8 +94,6 @@ source "drivers/staging/pi433/Kconfig" source "drivers/staging/mt7621-pci/Kconfig" -source "drivers/staging/mt7621-pci-phy/Kconfig" - source "drivers/staging/mt7621-pinctrl/Kconfig" source "drivers/staging/mt7621-dma/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 757a892ab5b9..39319161301c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -37,7 +37,6 @@ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_PI433) += pi433/ obj-$(CONFIG_PCI_MT7621) += mt7621-pci/ -obj-$(CONFIG_PCI_MT7621_PHY) += mt7621-pci-phy/ obj-$(CONFIG_PINCTRL_RT2880) += mt7621-pinctrl/ obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ diff --git a/drivers/staging/mt7621-pci-phy/Kconfig b/drivers/staging/mt7621-pci-phy/Kconfig deleted file mode 100644 index 263e0a91c424..000000000000 --- a/drivers/staging/mt7621-pci-phy/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config PCI_MT7621_PHY - tristate "MediaTek MT7621 PCI PHY Driver" - depends on RALINK && OF - select GENERIC_PHY - help - Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, - diff --git a/drivers/staging/mt7621-pci-phy/Makefile b/drivers/staging/mt7621-pci-phy/Makefile deleted file mode 100644 index b4d99b9119e0..000000000000 --- a/drivers/staging/mt7621-pci-phy/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PCI_MT7621_PHY) += pci-mt7621-phy.o diff --git a/drivers/staging/mt7621-pci-phy/TODO b/drivers/staging/mt7621-pci-phy/TODO deleted file mode 100644 index a255e8f753eb..000000000000 --- a/drivers/staging/mt7621-pci-phy/TODO +++ /dev/null @@ -1,4 +0,0 @@ - -- general code review and cleanup - -Cc: NeilBrown and Sergio Paracuellos diff --git a/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml b/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml deleted file mode 100644 index cf32bbc45b5d..000000000000 --- a/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" - -title: Mediatek Mt7621 PCIe PHY Device Tree Bindings - -maintainers: - - Sergio Paracuellos - -properties: - compatible: - const: mediatek,mt7621-pci-phy - - reg: - maxItems: 1 - - "#phy-cells": - const: 1 - description: selects if the phy is dual-ported - -required: - - compatible - - reg - - "#phy-cells" - -additionalProperties: false - -examples: - - | - pcie0_phy: pcie-phy at 1e149000 { - compatible = "mediatek,mt7621-pci-phy"; - reg = <0x1e149000 0x0700>; - #phy-cells = <1>; - }; diff --git a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c deleted file mode 100644 index 57743fd22be4..000000000000 --- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mediatek MT7621 PCI PHY Driver - * Author: Sergio Paracuellos - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RG_PE1_PIPE_REG 0x02c -#define RG_PE1_PIPE_RST BIT(12) -#define RG_PE1_PIPE_CMD_FRC BIT(4) - -#define RG_P0_TO_P1_WIDTH 0x100 -#define RG_PE1_H_LCDDS_REG 0x49c -#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) -#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) - -#define RG_PE1_FRC_H_XTAL_REG 0x400 -#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) -#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) -#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) - -#define RG_PE1_FRC_PHY_REG 0x000 -#define RG_PE1_FRC_PHY_EN BIT(4) -#define RG_PE1_PHY_EN BIT(5) - -#define RG_PE1_H_PLL_REG 0x490 -#define RG_PE1_H_PLL_BC GENMASK(23, 22) -#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) -#define RG_PE1_H_PLL_BP GENMASK(21, 18) -#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) -#define RG_PE1_H_PLL_IR GENMASK(15, 12) -#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) -#define RG_PE1_H_PLL_IC GENMASK(11, 8) -#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) -#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) -#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) -#define RG_PE1_PLL_DIVEN GENMASK(3, 1) -#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) - -#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc -#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) -#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) - -#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 -#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) -#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) - -#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 -#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) -#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) -#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) -#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) - -#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 -#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) - -#define RG_PE1_H_PLL_BR_REG 0x4ac -#define RG_PE1_H_PLL_BR GENMASK(18, 16) -#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) - -#define RG_PE1_MSTCKDIV_REG 0x414 -#define RG_PE1_MSTCKDIV GENMASK(7, 6) -#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) - -#define RG_PE1_FRC_MSTCKDIV BIT(5) - -#define XTAL_MODE_SEL_SHIFT 6 -#define XTAL_MODE_SEL_MASK 0x7 - -#define MAX_PHYS 2 - -/** - * struct mt7621_pci_phy - Mt7621 Pcie PHY core - * @dev: pointer to device - * @regmap: kernel regmap pointer - * @phy: pointer to the kernel PHY device - * @port_base: base register - * @has_dual_port: if the phy has dual ports. - * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst' - * needs to be executed. Depends on chip revision. - */ -struct mt7621_pci_phy { - struct device *dev; - struct regmap *regmap; - struct phy *phy; - void __iomem *port_base; - bool has_dual_port; - bool bypass_pipe_rst; -}; - -static inline u32 phy_read(struct mt7621_pci_phy *phy, u32 reg) -{ - u32 val; - - regmap_read(phy->regmap, reg, &val); - - return val; -} - -static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) -{ - regmap_write(phy->regmap, reg, val); -} - -static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, - u32 reg, u32 clr, u32 set) -{ - u32 val = phy_read(phy, reg); - - val &= ~clr; - val |= set; - phy_write(phy, val, reg); -} - -static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy) -{ - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST); - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC); - - if (phy->has_dual_port) { - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, - 0, RG_PE1_PIPE_RST); - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, - 0, RG_PE1_PIPE_CMD_FRC); - } -} - -static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) -{ - struct device *dev = phy->dev; - u32 xtal_mode; - - xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0) - >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; - - /* Set PCIe Port PHY to disable SSC */ - /* Debug Xtal Type */ - mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, - RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, - RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00)); - - /* disable port */ - mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - - if (phy->has_dual_port) { - mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - } - - if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ - /* Set Pre-divider ratio (for host mode) */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x01)); - dev_info(dev, "Xtal is 40MHz\n"); - } else if (xtal_mode >= 6) { /* 25MHz Xal */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x00)); - /* Select feedback clock */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, - RG_PE1_H_PLL_FBKSEL, - RG_PE1_H_PLL_FBKSEL_VAL(0x01)); - /* DDS NCPO PCW (for host mode) */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, - RG_PE1_H_LCDDS_SSC_PRD, - RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000)); - /* DDS SSC dither period control */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, - RG_PE1_H_LCDDS_SSC_PRD, - RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d)); - /* DDS SSC dither amplitude control */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, - RG_PE1_H_LCDDS_SSC_DELTA | - RG_PE1_H_LCDDS_SSC_DELTA1, - RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) | - RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a)); - dev_info(dev, "Xtal is 25MHz\n"); - } else { /* 20MHz Xtal */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x00)); - - dev_info(dev, "Xtal is 20MHz\n"); - } - - /* DDS clock inversion */ - mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG, - RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV); - - /* Set PLL bits */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | - RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN, - RG_PE1_H_PLL_BC_VAL(0x02) | RG_PE1_H_PLL_BP_VAL(0x06) | - RG_PE1_H_PLL_IR_VAL(0x02) | RG_PE1_H_PLL_IC_VAL(0x01) | - RG_PE1_PLL_DIVEN_VAL(0x02)); - - mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, - RG_PE1_H_PLL_BR, RG_PE1_H_PLL_BR_VAL(0x00)); - - if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ - /* set force mode enable of da_pe1_mstckdiv */ - mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG, - RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV, - RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV); - } -} - -static int mt7621_pci_phy_init(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - if (mphy->bypass_pipe_rst) - mt7621_bypass_pipe_rst(mphy); - - mt7621_set_phy_for_ssc(mphy); - - return 0; -} - -static int mt7621_pci_phy_power_on(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - /* Enable PHY and disable force mode */ - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, - RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); - - if (mphy->has_dual_port) { - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); - } - - return 0; -} - -static int mt7621_pci_phy_power_off(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - /* Disable PHY */ - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - - if (mphy->has_dual_port) { - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - } - - return 0; -} - -static int mt7621_pci_phy_exit(struct phy *phy) -{ - return 0; -} - -static const struct phy_ops mt7621_pci_phy_ops = { - .init = mt7621_pci_phy_init, - .exit = mt7621_pci_phy_exit, - .power_on = mt7621_pci_phy_power_on, - .power_off = mt7621_pci_phy_power_off, - .owner = THIS_MODULE, -}; - -static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) -{ - struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); - - if (WARN_ON(args->args[0] >= MAX_PHYS)) - return ERR_PTR(-ENODEV); - - mt7621_phy->has_dual_port = args->args[0]; - - dev_info(dev, "PHY for 0x%08x (dual port = %d)\n", - (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port); - - return mt7621_phy->phy; -} - -static const struct soc_device_attribute mt7621_pci_quirks_match[] = { - { .soc_id = "mt7621", .revision = "E2" } -}; - -static const struct regmap_config mt7621_pci_phy_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = 0x700, -}; - -static int mt7621_pci_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - const struct soc_device_attribute *attr; - struct phy_provider *provider; - struct mt7621_pci_phy *phy; - struct resource *res; - - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENOMEM; - - attr = soc_device_match(mt7621_pci_quirks_match); - if (attr) - phy->bypass_pipe_rst = true; - - phy->dev = dev; - platform_set_drvdata(pdev, phy); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get address resource\n"); - return -ENXIO; - } - - phy->port_base = devm_ioremap_resource(dev, res); - if (IS_ERR(phy->port_base)) { - dev_err(dev, "failed to remap phy regs\n"); - return PTR_ERR(phy->port_base); - } - - phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base, - &mt7621_pci_phy_regmap_config); - if (IS_ERR(phy->regmap)) - return PTR_ERR(phy->regmap); - - phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); - if (IS_ERR(phy)) { - dev_err(dev, "failed to create phy\n"); - return PTR_ERR(phy); - } - - phy_set_drvdata(phy->phy, phy); - - provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate); - - return PTR_ERR_OR_ZERO(provider); -} - -static const struct of_device_id mt7621_pci_phy_ids[] = { - { .compatible = "mediatek,mt7621-pci-phy" }, - {}, -}; -MODULE_DEVICE_TABLE(of, mt7621_pci_ids); - -static struct platform_driver mt7621_pci_phy_driver = { - .probe = mt7621_pci_phy_probe, - .driver = { - .name = "mt7621-pci-phy", - .of_match_table = of_match_ptr(mt7621_pci_phy_ids), - }, -}; - -builtin_platform_driver(mt7621_pci_phy_driver); - -MODULE_AUTHOR("Sergio Paracuellos "); -MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); -MODULE_LICENSE("GPL v2"); -- 2.25.1 From nano-sakuya at silk.ocn.ne.jp Thu Nov 19 16:22:45 2020 From: nano-sakuya at silk.ocn.ne.jp (=?UTF-8?B?5ZKy44GP44KE6Y2854G45pW06aqo6Zmi?=) Date: Thu, 19 Nov 2020 16:22:45 +0000 Subject: =?UTF-8?B?44Ob44O844Og44Oa44O844K444GL44KJ44Gu44GK5ZWP44GE5ZCI44KP44Gb?= Message-ID: <2e10ec08a7ac9aa6b96e580aec705af3@www.sakuya-shinkyu.net> ? I'm waiting for you... Answer me here: http://bit.do/fLcJN?tqcas ? ? ???????????????????????????????? ???????????????? ??????????????????????? ??????????????????? ?????????????????? ??????????????? From huanggf at par.cse.nsysu.edu.tw Thu Nov 19 15:11:58 2020 From: huanggf at par.cse.nsysu.edu.tw (COCA COLA.) Date: Thu, 19 Nov 2020 07:11:58 -0800 Subject: COCA-COLA LOTTERY ORGANIZATION. Message-ID: <20201119194255.9FCD086EA1@whitealder.osuosl.org> COCA-COLA LOTTERY ORGANIZATION TICKET FREE/ONLINE E-MAIL ADDRESS WINNINGS DEPARTMENT. Greetings Winner, If you are the correct owner of this email address? If yes then be glad this day as the result of the Coca-Cola lotto online e-mail address free-ticket winning draws of July 2020 ,held in United States of America has just been released and we are glad to announce to you that your email address won you the sweepstakes in the first category and you are entitled to claim the sum of One Million Two Hundred And Fifty Thousand United States Dollars(US$1,250,000.00). Your email address was entered for the online draw on this ticket No: 546-373-66773 and won on this Lucky No: (14)-(8)-(5)-(19)-(28)-(12)-(30). On how to receive your won prize of US$1.250,000.00M. (One Million Two Hundred And Fifty Thousand United States Dollars Only) to enable Mr.James Curtise ascertain you as the rightful winner and receiver of the US$1.250,000.00M.Make sure you include the below listed information in your contact email to him. Your complete official names, country of origin and country of residence/work, contact telephone and mobile numbers, amount won,lucky numbers, date of draw. OPTIONAL: - [Sex, age, occupation and job title]. Just in case you are thinking of how you won without entering then know again that this very draw of the Coca-Cola Lottery Organization in which you have emerged as a winner was a free ticket online email address draws were thousands of email addresses was collected from almost all world wide websites and used for the online draws/sweepstakes and during winners selection your email address came out among the first ten which won you the lottery in the first winnings category and entitles you to claim the US$1,250,000.00 dollars. Yours Faithfully, Mr.James Curtise COCA-COLA LOTTERY ORGANIZATION. Online Winning Notification Department. Tel: +1-403-607-1548 From huanggf at par.cse.nsysu.edu.tw Thu Nov 19 16:00:45 2020 From: huanggf at par.cse.nsysu.edu.tw (COCA COLA.) Date: Thu, 19 Nov 2020 08:00:45 -0800 Subject: COCA-COLA LOTTERY ORGANIZATION. Message-ID: <20201119203201.8A40086FFE@hemlock.osuosl.org> COCA-COLA LOTTERY ORGANIZATION TICKET FREE/ONLINE E-MAIL ADDRESS WINNINGS DEPARTMENT. Greetings Winner, If you are the correct owner of this email address? If yes then be glad this day as the result of the Coca-Cola lotto online e-mail address free-ticket winning draws of July 2020 ,held in United States of America has just been released and we are glad to announce to you that your email address won you the sweepstakes in the first category and you are entitled to claim the sum of One Million Two Hundred And Fifty Thousand United States Dollars(US$1,250,000.00). Your email address was entered for the online draw on this ticket No: 546-373-66773 and won on this Lucky No: (14)-(8)-(5)-(19)-(28)-(12)-(30). On how to receive your won prize of US$1.250,000.00M. (One Million Two Hundred And Fifty Thousand United States Dollars Only) to enable Mr.James Curtise ascertain you as the rightful winner and receiver of the US$1.250,000.00M.Make sure you include the below listed information in your contact email to him. Your complete official names, country of origin and country of residence/work, contact telephone and mobile numbers, amount won,lucky numbers, date of draw. OPTIONAL: - [Sex, age, occupation and job title]. Just in case you are thinking of how you won without entering then know again that this very draw of the Coca-Cola Lottery Organization in which you have emerged as a winner was a free ticket online email address draws were thousands of email addresses was collected from almost all world wide websites and used for the online draws/sweepstakes and during winners selection your email address came out among the first ten which won you the lottery in the first winnings category and entitles you to claim the US$1,250,000.00 dollars. Yours Faithfully, Mr.James Curtise COCA-COLA LOTTERY ORGANIZATION. Online Winning Notification Department. Tel: +1-403-607-1548 From agatha.tan at homeequity.com.sg Thu Nov 19 20:19:14 2020 From: agatha.tan at homeequity.com.sg (Dr.Henry Biko) Date: Fri, 20 Nov 2020 04:19:14 +0800 Subject: hello Message-ID: <4f739edea4c244528b08b3dcea64e9e8@homeequity.com.sg> Hello Mr William Connor gave instructions to send to you $950,000.00 USD ATM VISA CASH CARD to your address before he travel out of this country, please re-confirm your details to enable me proceed to DHL courier for delivery Thanks, Best Regards, Dr.Henry Biko From agatha.tan at homeequity.com.sg Thu Nov 19 20:19:26 2020 From: agatha.tan at homeequity.com.sg (Dr.Henry Biko) Date: Fri, 20 Nov 2020 04:19:26 +0800 Subject: hello Message-ID: Hello Mr William Connor gave instructions to send to you $950,000.00 USD ATM VISA CASH CARD to your address before he travel out of this country, please re-confirm your details to enable me proceed to DHL courier for delivery Thanks, Best Regards, Dr.Henry Biko From agatha.tan at homeequity.com.sg Thu Nov 19 20:20:21 2020 From: agatha.tan at homeequity.com.sg (Dr.Henry Biko) Date: Fri, 20 Nov 2020 04:20:21 +0800 Subject: hello Message-ID: Hello Mr William Connor gave instructions to send to you $950,000.00 USD ATM VISA CASH CARD to your address before he travel out of this country, please re-confirm your details to enable me proceed to DHL courier for delivery Thanks, Best Regards, Dr.Henry Biko From nami at 4sasa.xyz Fri Nov 20 04:12:38 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Fri, 20 Nov 2020 12:12:38 +0800 Subject: GREETINGS DEAR BELOVED: Message-ID: <20201120041327.B7EC086DB4@fraxinus.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Marylyne vantelli Email:marylynevantelli248 at gmail.com From nami at 4sasa.xyz Fri Nov 20 04:12:38 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Fri, 20 Nov 2020 12:12:38 +0800 Subject: GREETINGS DEAR BELOVED: Message-ID: <20201120041327.B7E3686DB2@fraxinus.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Marylyne vantelli Email:marylynevantelli248 at gmail.com From nami at 4sasa.xyz Fri Nov 20 04:33:52 2020 From: nami at 4sasa.xyz (Ms. Marylyne Vantelli) Date: Fri, 20 Nov 2020 12:33:52 +0800 Subject: GREETINGS DEAR BELOVED: Message-ID: <20201120043402.7CCC787580@hemlock.osuosl.org> Dear Beloved, Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of ?10,000,000.00 Euro (Ten Million EUR) to you. On your acknowledgment of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity. Sincere regards, Ms. Marylyne vantelli Email:marylynevantelli248 at gmail.com From ictsa at taiz.edu.ye Thu Nov 19 03:34:45 2020 From: ictsa at taiz.edu.ye (Hello) Date: Thu, 19 Nov 2020 03:34:45 -0000 Subject: Hello friend 19/11/2020 Message-ID: <35C7E6AC4BA04847924E0AF40FAA2ADF.MAI@taiz.edu.ye> My name is Reem Hashimy, the Emirates Minister of State and Managing Director of the United Arab Emirates (Dubai) World Expo 2020 Committee which has been postponed to October 2021 to March 2022 because of the Covid-19 pandemic. I am writing to you to manage the funds I received as financial gratification from various foreign companies I assisted to receive a participation approval to the coming event. The amount is $44,762,906.00 United States dollars. But I can not personally manage the fund in my country because of the sensitive nature of my office and the certain restriction on married Muslim women. For this reason, an agreement was reached with a consulting firm to direct the various financial gifts into an open beneficiary account in my name with a bank where it will be possible for me to instruct the transfer of ownership right to a third party for investment purpose; which is the reason I am contacting you to receive the fund and manage it as my investment partner. Note that the fund is NOT connected to any criminal or terrorist activity. On your indication of interest with your information to include your name, your phone number and contact mailing address; I will instruct the consulting firm to process the fund from the bank to your country for investment purposes. Regards. Reem Hashimy. From wordpress at takuma-onishi.com Fri Nov 20 07:03:37 2020 From: wordpress at takuma-onishi.com (takuma onishi) Date: Fri, 20 Nov 2020 07:03:37 +0000 Subject: =?UTF-8?Q?=F0=9F=92=BC_Ride_the_wave_of_bitcoins_and_earn_guaranteed_13, 0?= =?UTF-8?Q?00$_in_exactly_24_hours, _follow_the_personal_link:_https://mill?= =?UTF-8?Q?ionairego.page.link/de=3F76a_=F0=9F=92=BC?= Message-ID: <35f77345bee8855743a13011682f67bd@takuma-onishi.com> ???????: ? Ride the wave of bitcoins and earn guaranteed 13,000$ in exactly 24 hours, follow the personal link: https://millionairego.page.link/de?76a ? -- ?????? takuma onishi (http://takuma-onishi.com) ???????????????????? From jingxiangfeng at huawei.com Fri Nov 20 07:49:32 2020 From: jingxiangfeng at huawei.com (Jing Xiangfeng) Date: Fri, 20 Nov 2020 15:49:32 +0800 Subject: [PATCH] staging: olpc_dcon: Do not call platform_device_unregister() in dcon_probe() Message-ID: <20201120074932.31871-1-jingxiangfeng@huawei.com> In dcon_probe(), when platform_device_add() failes to add the device, it jumps to call platform_device_unregister() to remove the device, which is unnecessary. So use platform_device_put() instead. Fixes: 53c43c5ca133 ("Revert "Staging: olpc_dcon: Remove obsolete driver"") Signed-off-by: Jing Xiangfeng --- drivers/staging/olpc_dcon/olpc_dcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index a0d6d90f4cc8..e7281212db5b 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -659,8 +659,9 @@ static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) ecreate: for (j = 0; j < i; j++) device_remove_file(&dcon_device->dev, &dcon_device_files[j]); + platform_device_del(dcon_device); edev: - platform_device_unregister(dcon_device); + platform_device_put(dcon_device); dcon_device = NULL; eirq: free_irq(DCON_IRQ, dcon); -- 2.17.1 From sorbar at 126.com Fri Nov 20 15:15:43 2020 From: sorbar at 126.com (Robert) Date: Fri, 20 Nov 2020 23:15:43 +0800 Subject: Packaging Bag Message-ID: <20201120152651.4641986F17@fraxinus.osuosl.org> Hello Sir/Madam, Do you need professional advice on packaging bag ? I'm Robert from Sorbar Flexible Packaging. We are the Chinese packaging bag factory establised in 2015. We specilize in OEM/ODM packaging over 5 years. If you have any project need to produce in China, welcome to let us know. Or if you have any problem about the packaging bag, please hestiate to contact us. Maybe we can make your businese more profitable. Best Regards Robert.Luo | Sorbar Packaging| www.sorbar.com E-mail: robert.luo at sorbar.com Facebook:@sorbarpackaging Address: No.1 Street, Matan Village Luoma District, Qingxi Town,Dongguan City,China From financialcapability6 at gmail.com Fri Nov 20 14:42:30 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Fri, 20 Nov 2020 06:42:30 -0800 Subject: Corporate and Personal Loan ,t Message-ID: <20201120153504.BEC8E20397@silver.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From sergio.paracuellos at gmail.com Fri Nov 20 16:20:32 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Fri, 20 Nov 2020 17:20:32 +0100 Subject: [PATCH v5 0/4] MT7621 PCIe PHY In-Reply-To: <20201119154337.9195-1-sergio.paracuellos@gmail.com> References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: Hi Vinod, On Thu, Nov 19, 2020 at 4:43 PM Sergio Paracuellos wrote: > > This series adds support for the PCIe PHY found in the Mediatek > MT7621 SoC. > > There is also a 'mt7621-pci' driver which is the controller part > which is still in staging and is a client of this phy. > > Both drivers have been tested together in a gnubee1 board. > > This series are rebased on the top of linux-next: > commit 4e78c578cb98 ("Add linux-next specific files for 20201030") > > Changes in v5: > - PATCH 1/4: Recollect Rob's Reviewed-by of bindings. > - PATCH 4/4: Recollect Greg's Acked-by for removing stuff from > staging area. > - Make Vinod's review comments changes in [0]: > * Use FIELD_GET and FIELD_PREP apis and avoid multiple *_VAL and > *_SHIFT custom definitions. > * Remove phy-read and phy-write internal functions and directly > call regmap_read and regmap_write in 'mt7621_phy_rmw'. > * Change some traces from info to debug log level. > * Note that I have maintained 'mt7621_phy_rmw' instead of use > 'regmap_update_bits'. This is because in order to get a reliable > boot registers must be written event the contained value in > that register is the same. I have preferred doing in this way > instead of using 'regmap_update_bits_base' passing 'false' for > async and 'true' for the force write. If this way of using > 'regmap_update_bits_base' is preferred just let me know. I notice we already have 'regmap_write_bits' function. I will use this and avoid mt7621_phy_rmw and send v6 of this series. Also, do you have any preference of where you want this series to be rebased on? Best regards, Sergio Paracuellos > > Changes in v4: > - Bindings moved from txt to yaml so previous Rob's Reviewed-by > is not in the new patch with the yaml file. > - 'phy-cells' property means now if phy is dual-ported. > - Avoid custom 'xlate' function and properly set registers > when the phy is dual ported. > - Add use of 'builtin_platform_driver'. > - Added a patch including myself as maintainer in the > MAINTAINERS file. > - Add a patch removing patch from staging to make easier > the complete inclusion and avoid possible problems might > appear in 'linux-next' if the series are included. > > Changes in v3: > - Recollect Rob's Reviewed-by of bindings. > - Make Kishon Vijay suggested changes in v2: > (See https://lkml.org/lkml/2019/4/17/53) > - Kconfig: > * Add depends on COMPILE_TEST > * Select REGMAP_MMIO > - Make use of 'soc_device_attribute' and 'soc_device_match' > - Use regmap mmio API instead of directly 'readl' and 'writel'. > - Use 'platform_get_resource' instead of 'of_address_to_resource'. > > Changes in v2: > - Reorder patches to get bindings first in the series. > - Don't use child nodes in the device tree. Use #phy-cells=1 instead. > - Update driver code with new 'xlate' function for the new device tree. > - Minor changes in driver's macros changing some spaces to tabs. > > Thanks in advance for your time. > > Best regards, > Sergio Paracuellos > > [0]: http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2020-November/148864.html > > Sergio Paracuellos (4): > dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY > phy: ralink: Add PHY driver for MT7621 PCIe PHY > MAINTAINERS: add MT7621 PHY PCI maintainer > staging: mt7621-pci-phy: remove driver from staging > > .../phy}/mediatek,mt7621-pci-phy.yaml | 0 > MAINTAINERS | 6 + > drivers/phy/ralink/Kconfig | 8 ++ > drivers/phy/ralink/Makefile | 1 + > .../ralink/phy-mt7621-pci.c} | 103 +++++++----------- > drivers/staging/Kconfig | 2 - > drivers/staging/Makefile | 1 - > drivers/staging/mt7621-pci-phy/Kconfig | 8 -- > drivers/staging/mt7621-pci-phy/Makefile | 2 - > drivers/staging/mt7621-pci-phy/TODO | 4 - > 10 files changed, 53 insertions(+), 82 deletions(-) > rename {drivers/staging/mt7621-pci-phy => Documentation/devicetree/bindings/phy}/mediatek,mt7621-pci-phy.yaml (100%) > rename drivers/{staging/mt7621-pci-phy/pci-mt7621-phy.c => phy/ralink/phy-mt7621-pci.c} (76%) > delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig > delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile > delete mode 100644 drivers/staging/mt7621-pci-phy/TODO > > -- > 2.25.1 > From dan.carpenter at oracle.com Fri Nov 20 16:27:18 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Fri, 20 Nov 2020 19:27:18 +0300 Subject: [PATCH] media: atomisp: Fix a buffer overflow in debug code Message-ID: <20201120162718.GA3506662@mwanda> The "pad" variable is a user controlled string and we haven't properly clamped it at this point so the debug code could print from beyond the of the array. Fixes: a49d25364dfb ("staging/atomisp: Add support for the Intel IPU v2") Signed-off-by: Dan Carpenter --- Not tested. .../media/atomisp/pci/atomisp_subdev.c | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/atomisp/pci/atomisp_subdev.c b/drivers/staging/media/atomisp/pci/atomisp_subdev.c index 52b9fb18c87f..dcc2dd981ca6 100644 --- a/drivers/staging/media/atomisp/pci/atomisp_subdev.c +++ b/drivers/staging/media/atomisp/pci/atomisp_subdev.c @@ -349,12 +349,20 @@ static int isp_subdev_get_selection(struct v4l2_subdev *sd, return 0; } -static char *atomisp_pad_str[] = { "ATOMISP_SUBDEV_PAD_SINK", - "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE", - "ATOMISP_SUBDEV_PAD_SOURCE_VF", - "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW", - "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO" - }; +static const char *atomisp_pad_str(unsigned int pad) +{ + static const char *const pad_str[] = { + "ATOMISP_SUBDEV_PAD_SINK", + "ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE", + "ATOMISP_SUBDEV_PAD_SOURCE_VF", + "ATOMISP_SUBDEV_PAD_SOURCE_PREVIEW", + "ATOMISP_SUBDEV_PAD_SOURCE_VIDEO", + }; + + if (pad >= ARRAY_SIZE(pad_str)) + return "ATOMISP_INVALID_PAD"; + return pad_str[pad]; +} int atomisp_subdev_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, @@ -378,7 +386,7 @@ int atomisp_subdev_set_selection(struct v4l2_subdev *sd, dev_dbg(isp->dev, "sel: pad %s tgt %s l %d t %d w %d h %d which %s f 0x%8.8x\n", - atomisp_pad_str[pad], target == V4L2_SEL_TGT_CROP + atomisp_pad_str(pad), target == V4L2_SEL_TGT_CROP ? "V4L2_SEL_TGT_CROP" : "V4L2_SEL_TGT_COMPOSE", r->left, r->top, r->width, r->height, which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" @@ -612,7 +620,7 @@ void atomisp_subdev_set_ffmt(struct v4l2_subdev *sd, enum atomisp_input_stream_id stream_id; dev_dbg(isp->dev, "ffmt: pad %s w %d h %d code 0x%8.8x which %s\n", - atomisp_pad_str[pad], ffmt->width, ffmt->height, ffmt->code, + atomisp_pad_str(pad), ffmt->width, ffmt->height, ffmt->code, which == V4L2_SUBDEV_FORMAT_TRY ? "V4L2_SUBDEV_FORMAT_TRY" : "V4L2_SUBDEV_FORMAT_ACTIVE"); -- 2.29.2 From gustavoars at kernel.org Fri Nov 20 18:21:39 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:21:39 -0600 Subject: [PATCH 000/141] Fix fall-through warnings for Clang Message-ID: Hi all, This series aims to fix almost all remaining fall-through warnings in order to enable -Wimplicit-fallthrough for Clang. In preparation to enable -Wimplicit-fallthrough for Clang, explicitly add multiple break/goto/return/fallthrough statements instead of just letting the code fall through to the next case. Notice that in order to enable -Wimplicit-fallthrough for Clang, this change[1] is meant to be reverted at some point. So, this patch helps to move in that direction. Something important to mention is that there is currently a discrepancy between GCC and Clang when dealing with switch fall-through to empty case statements or to cases that only contain a break/continue/return statement[2][3][4]. Now that the -Wimplicit-fallthrough option has been globally enabled[5], any compiler should really warn on missing either a fallthrough annotation or any of the other case-terminating statements (break/continue/return/ goto) when falling through to the next case statement. Making exceptions to this introduces variation in case handling which may continue to lead to bugs, misunderstandings, and a general lack of robustness. The point of enabling options like -Wimplicit-fallthrough is to prevent human error and aid developers in spotting bugs before their code is even built/ submitted/committed, therefore eliminating classes of bugs. So, in order to really accomplish this, we should, and can, move in the direction of addressing any error-prone scenarios and get rid of the unintentional fallthrough bug-class in the kernel, entirely, even if there is some minor redundancy. Better to have explicit case-ending statements than continue to have exceptions where one must guess as to the right result. The compiler will eliminate any actual redundancy. Note that there is already a patch in mainline that addresses almost 40,000 of these issues[6]. I'm happy to carry this whole series in my own tree if people are OK with it. :) [1] commit e2079e93f562c ("kbuild: Do not enable -Wimplicit-fallthrough for clang for now") [2] ClangBuiltLinux#636 [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91432 [4] https://godbolt.org/z/xgkvIh [5] commit a035d552a93b ("Makefile: Globally enable fall-through warning") [6] commit 4169e889e588 ("include: jhash/signal: Fix fall-through warnings for Clang") Thanks! Gustavo A. R. Silva (141): afs: Fix fall-through warnings for Clang ASoC: codecs: Fix fall-through warnings for Clang cifs: Fix fall-through warnings for Clang drm/amdgpu: Fix fall-through warnings for Clang drm/radeon: Fix fall-through warnings for Clang gfs2: Fix fall-through warnings for Clang gpio: Fix fall-through warnings for Clang IB/hfi1: Fix fall-through warnings for Clang igb: Fix fall-through warnings for Clang ima: Fix fall-through warnings for Clang ipv4: Fix fall-through warnings for Clang ixgbe: Fix fall-through warnings for Clang media: dvb-frontends: Fix fall-through warnings for Clang media: usb: dvb-usb-v2: Fix fall-through warnings for Clang netfilter: Fix fall-through warnings for Clang nfsd: Fix fall-through warnings for Clang nfs: Fix fall-through warnings for Clang qed: Fix fall-through warnings for Clang qlcnic: Fix fall-through warnings for Clang scsi: aic7xxx: Fix fall-through warnings for Clang scsi: aic94xx: Fix fall-through warnings for Clang scsi: bfa: Fix fall-through warnings for Clang staging: rtl8723bs: core: Fix fall-through warnings for Clang staging: vt6655: Fix fall-through warnings for Clang bnxt_en: Fix fall-through warnings for Clang ceph: Fix fall-through warnings for Clang drbd: Fix fall-through warnings for Clang drm/amd/display: Fix fall-through warnings for Clang e1000: Fix fall-through warnings for Clang ext2: Fix fall-through warnings for Clang ext4: Fix fall-through warnings for Clang floppy: Fix fall-through warnings for Clang fm10k: Fix fall-through warnings for Clang IB/mlx4: Fix fall-through warnings for Clang IB/qedr: Fix fall-through warnings for Clang ice: Fix fall-through warnings for Clang Input: pcspkr - Fix fall-through warnings for Clang isofs: Fix fall-through warnings for Clang ixgbevf: Fix fall-through warnings for Clang kprobes/x86: Fix fall-through warnings for Clang mm: Fix fall-through warnings for Clang net: 3c509: Fix fall-through warnings for Clang net: cassini: Fix fall-through warnings for Clang net/mlx4: Fix fall-through warnings for Clang net: mscc: ocelot: Fix fall-through warnings for Clang netxen_nic: Fix fall-through warnings for Clang nfp: Fix fall-through warnings for Clang perf/x86: Fix fall-through warnings for Clang pinctrl: Fix fall-through warnings for Clang RDMA/mlx5: Fix fall-through warnings for Clang reiserfs: Fix fall-through warnings for Clang security: keys: Fix fall-through warnings for Clang selinux: Fix fall-through warnings for Clang target: Fix fall-through warnings for Clang uprobes/x86: Fix fall-through warnings for Clang vxge: Fix fall-through warnings for Clang watchdog: Fix fall-through warnings for Clang xen-blkfront: Fix fall-through warnings for Clang regulator: as3722: Fix fall-through warnings for Clang habanalabs: Fix fall-through warnings for Clang tee: Fix fall-through warnings for Clang HID: usbhid: Fix fall-through warnings for Clang HID: input: Fix fall-through warnings for Clang ACPI: Fix fall-through warnings for Clang airo: Fix fall-through warnings for Clang ALSA: hdspm: Fix fall-through warnings for Clang ALSA: pcsp: Fix fall-through warnings for Clang ALSA: sb: Fix fall-through warnings for Clang ath5k: Fix fall-through warnings for Clang atm: fore200e: Fix fall-through warnings for Clang braille_console: Fix fall-through warnings for Clang can: peak_usb: Fix fall-through warnings for Clang carl9170: Fix fall-through warnings for Clang cfg80211: Fix fall-through warnings for Clang crypto: ccree - Fix fall-through warnings for Clang decnet: Fix fall-through warnings for Clang dm raid: Fix fall-through warnings for Clang drm/amd/pm: Fix fall-through warnings for Clang drm: Fix fall-through warnings for Clang drm/i915/gem: Fix fall-through warnings for Clang drm/nouveau/clk: Fix fall-through warnings for Clang drm/nouveau: Fix fall-through warnings for Clang drm/nouveau/therm: Fix fall-through warnings for Clang drm/via: Fix fall-through warnings for Clang firewire: core: Fix fall-through warnings for Clang hwmon: (corsair-cpro) Fix fall-through warnings for Clang hwmon: (max6621) Fix fall-through warnings for Clang i3c: master: cdns: Fix fall-through warnings for Clang ide: Fix fall-through warnings for Clang iio: adc: cpcap: Fix fall-through warnings for Clang iwlwifi: iwl-drv: Fix fall-through warnings for Clang libata: Fix fall-through warnings for Clang mac80211: Fix fall-through warnings for Clang media: atomisp: Fix fall-through warnings for Clang media: dvb_frontend: Fix fall-through warnings for Clang media: rcar_jpu: Fix fall-through warnings for Clang media: saa7134: Fix fall-through warnings for Clang mmc: sdhci-of-arasan: Fix fall-through warnings for Clang mt76: mt7615: Fix fall-through warnings for Clang mtd: cfi: Fix fall-through warnings for Clang mtd: mtdchar: Fix fall-through warnings for Clang mtd: onenand: Fix fall-through warnings for Clang mtd: rawnand: fsmc: Fix fall-through warnings for Clang mtd: rawnand: stm32_fmc2: Fix fall-through warnings for Clang net: ax25: Fix fall-through warnings for Clang net: bridge: Fix fall-through warnings for Clang net: core: Fix fall-through warnings for Clang netfilter: ipt_REJECT: Fix fall-through warnings for Clang net: netrom: Fix fall-through warnings for Clang net/packet: Fix fall-through warnings for Clang net: plip: Fix fall-through warnings for Clang net: rose: Fix fall-through warnings for Clang nl80211: Fix fall-through warnings for Clang phy: qcom-usb-hs: Fix fall-through warnings for Clang rds: Fix fall-through warnings for Clang rt2x00: Fix fall-through warnings for Clang rtl8xxxu: Fix fall-through warnings for Clang rtw88: Fix fall-through warnings for Clang rxrpc: Fix fall-through warnings for Clang scsi: aacraid: Fix fall-through warnings for Clang scsi: aha1740: Fix fall-through warnings for Clang scsi: csiostor: Fix fall-through warnings for Clang scsi: lpfc: Fix fall-through warnings for Clang scsi: stex: Fix fall-through warnings for Clang sctp: Fix fall-through warnings for Clang slimbus: messaging: Fix fall-through warnings for Clang staging: qlge: Fix fall-through warnings for Clang staging: vt6656: Fix fall-through warnings for Clang SUNRPC: Fix fall-through warnings for Clang tipc: Fix fall-through warnings for Clang tpm: Fix fall-through warnings for Clang ubi: Fix fall-through warnings for Clang usb: Fix fall-through warnings for Clang video: fbdev: lxfb_ops: Fix fall-through warnings for Clang video: fbdev: pm2fb: Fix fall-through warnings for Clang virtio_net: Fix fall-through warnings for Clang wcn36xx: Fix fall-through warnings for Clang xen/manage: Fix fall-through warnings for Clang xfrm: Fix fall-through warnings for Clang zd1201: Fix fall-through warnings for Clang Input: libps2 - Fix fall-through warnings for Clang arch/x86/events/core.c | 2 +- arch/x86/kernel/kprobes/core.c | 1 + arch/x86/kernel/uprobes.c | 2 ++ drivers/accessibility/braille/braille_console.c | 1 + drivers/acpi/sbshc.c | 1 + drivers/ata/libata-eh.c | 1 + drivers/atm/fore200e.c | 1 + drivers/block/drbd/drbd_receiver.c | 1 + drivers/block/drbd/drbd_req.c | 1 + drivers/block/floppy.c | 1 + drivers/block/xen-blkfront.c | 1 + drivers/char/tpm/eventlog/tpm1.c | 1 + drivers/crypto/ccree/cc_cipher.c | 3 +++ drivers/firewire/core-topology.c | 1 + drivers/gpio/gpio-ath79.c | 1 + drivers/gpio/gpiolib-acpi.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c | 1 + drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c | 1 + drivers/gpu/drm/amd/amdgpu/vi.c | 1 + drivers/gpu/drm/amd/display/dc/bios/bios_parser.c | 1 + drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c | 2 ++ drivers/gpu/drm/amd/display/dc/core/dc_link.c | 1 + drivers/gpu/drm/amd/pm/powerplay/si_dpm.c | 2 +- .../gpu/drm/amd/pm/powerplay/smumgr/polaris10_smumgr.c | 1 + drivers/gpu/drm/drm_bufs.c | 1 + drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 1 + drivers/gpu/drm/nouveau/nouveau_bo.c | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c | 1 + drivers/gpu/drm/radeon/ci_dpm.c | 2 +- drivers/gpu/drm/radeon/r300.c | 1 + drivers/gpu/drm/radeon/si_dpm.c | 2 +- drivers/gpu/drm/via/via_irq.c | 1 + drivers/hid/hid-input.c | 1 + drivers/hid/usbhid/hid-core.c | 2 ++ drivers/hwmon/corsair-cpro.c | 1 + drivers/hwmon/max6621.c | 2 +- drivers/i3c/master/i3c-master-cdns.c | 2 ++ drivers/ide/siimage.c | 1 + drivers/iio/adc/cpcap-adc.c | 1 + drivers/infiniband/hw/hfi1/qp.c | 1 + drivers/infiniband/hw/hfi1/tid_rdma.c | 5 +++++ drivers/infiniband/hw/mlx4/mad.c | 1 + drivers/infiniband/hw/mlx5/qp.c | 1 + drivers/infiniband/hw/qedr/main.c | 1 + drivers/input/misc/pcspkr.c | 1 + drivers/input/serio/libps2.c | 2 +- drivers/md/dm-raid.c | 1 + drivers/media/dvb-core/dvb_frontend.c | 1 + drivers/media/dvb-frontends/cx24120.c | 1 + drivers/media/dvb-frontends/dib0090.c | 2 ++ drivers/media/dvb-frontends/drxk_hard.c | 1 + drivers/media/dvb-frontends/m88rs2000.c | 1 + drivers/media/pci/saa7134/saa7134-tvaudio.c | 1 + drivers/media/platform/rcar_jpu.c | 1 + drivers/media/usb/dvb-usb-v2/af9015.c | 1 + drivers/media/usb/dvb-usb-v2/lmedm04.c | 1 + drivers/misc/habanalabs/gaudi/gaudi.c | 1 + drivers/mmc/host/sdhci-of-arasan.c | 4 ++++ drivers/mtd/chips/cfi_cmdset_0001.c | 1 + drivers/mtd/chips/cfi_cmdset_0002.c | 2 ++ drivers/mtd/chips/cfi_cmdset_0020.c | 2 ++ drivers/mtd/mtdchar.c | 1 + drivers/mtd/nand/onenand/onenand_samsung.c | 1 + drivers/mtd/nand/raw/fsmc_nand.c | 1 + drivers/mtd/nand/raw/stm32_fmc2_nand.c | 2 ++ drivers/mtd/ubi/build.c | 1 + drivers/net/can/usb/peak_usb/pcan_usb_core.c | 2 ++ drivers/net/ethernet/3com/3c509.c | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + drivers/net/ethernet/intel/e1000/e1000_hw.c | 1 + drivers/net/ethernet/intel/fm10k/fm10k_mbx.c | 2 ++ drivers/net/ethernet/intel/ice/ice_txrx_lib.c | 1 + drivers/net/ethernet/intel/igb/e1000_phy.c | 1 + drivers/net/ethernet/intel/igb/igb_ethtool.c | 1 + drivers/net/ethernet/intel/igb/igb_ptp.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 2 ++ drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 1 + drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 1 + drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 1 + drivers/net/ethernet/mscc/ocelot_vcap.c | 1 + drivers/net/ethernet/neterion/vxge/vxge-config.c | 1 + drivers/net/ethernet/netronome/nfp/nfp_net_repr.c | 1 + drivers/net/ethernet/qlogic/netxen/netxen_nic_init.c | 1 + drivers/net/ethernet/qlogic/qed/qed_l2.c | 1 + drivers/net/ethernet/qlogic/qed/qed_sriov.c | 1 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 1 + drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 + drivers/net/ethernet/sun/cassini.c | 1 + drivers/net/plip/plip.c | 2 ++ drivers/net/virtio_net.c | 1 + drivers/net/wireless/ath/ath5k/mac80211-ops.c | 1 + drivers/net/wireless/ath/carl9170/tx.c | 1 + drivers/net/wireless/ath/wcn36xx/smd.c | 2 +- drivers/net/wireless/cisco/airo.c | 1 + drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 +- drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c | 2 +- drivers/net/wireless/ralink/rt2x00/rt2x00queue.c | 1 + drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 8 ++++---- drivers/net/wireless/realtek/rtw88/fw.c | 2 +- drivers/net/wireless/zydas/zd1201.c | 2 +- drivers/phy/qualcomm/phy-qcom-usb-hs.c | 1 + drivers/pinctrl/renesas/pinctrl-rza1.c | 1 + drivers/regulator/as3722-regulator.c | 3 ++- drivers/scsi/aacraid/commsup.c | 1 + drivers/scsi/aha1740.c | 1 + drivers/scsi/aic7xxx/aic79xx_core.c | 4 +++- drivers/scsi/aic7xxx/aic7xxx_core.c | 4 ++-- drivers/scsi/aic94xx/aic94xx_scb.c | 2 ++ drivers/scsi/aic94xx/aic94xx_task.c | 2 ++ drivers/scsi/bfa/bfa_fcs_lport.c | 2 +- drivers/scsi/bfa/bfa_ioc.c | 6 ++++-- drivers/scsi/csiostor/csio_wr.c | 1 + drivers/scsi/lpfc/lpfc_bsg.c | 1 + drivers/scsi/stex.c | 1 + drivers/slimbus/messaging.c | 1 + drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 1 + drivers/staging/qlge/qlge_main.c | 1 + drivers/staging/rtl8723bs/core/rtw_cmd.c | 1 + drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 1 + drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 1 + drivers/staging/vt6655/device_main.c | 1 + drivers/staging/vt6655/rxtx.c | 2 ++ drivers/staging/vt6656/main_usb.c | 1 + drivers/target/target_core_iblock.c | 1 + drivers/target/target_core_pr.c | 1 + drivers/tee/tee_core.c | 1 + drivers/usb/gadget/function/f_fs.c | 2 ++ drivers/usb/gadget/function/f_loopback.c | 2 +- drivers/usb/gadget/function/f_sourcesink.c | 1 + drivers/usb/gadget/udc/dummy_hcd.c | 2 ++ drivers/usb/host/fotg210-hcd.c | 2 +- drivers/usb/host/isp116x-hcd.c | 1 + drivers/usb/host/max3421-hcd.c | 1 + drivers/usb/host/oxu210hp-hcd.c | 1 + drivers/usb/misc/yurex.c | 1 + drivers/usb/musb/tusb6010.c | 1 + drivers/usb/storage/ene_ub6250.c | 1 + drivers/usb/storage/uas.c | 1 + drivers/video/fbdev/geode/lxfb_ops.c | 1 + drivers/video/fbdev/pm2fb.c | 1 + drivers/watchdog/machzwd.c | 1 + drivers/xen/manage.c | 1 + fs/afs/cmservice.c | 5 +++++ fs/afs/fsclient.c | 4 ++++ fs/afs/vlclient.c | 1 + fs/ceph/dir.c | 2 ++ fs/cifs/inode.c | 1 + fs/cifs/sess.c | 1 + fs/cifs/smbdirect.c | 1 + fs/ext2/inode.c | 1 + fs/ext4/super.c | 1 + fs/gfs2/inode.c | 2 ++ fs/gfs2/recovery.c | 1 + fs/isofs/rock.c | 1 + fs/nfs/nfs3acl.c | 1 + fs/nfs/nfs4client.c | 1 + fs/nfs/nfs4proc.c | 2 ++ fs/nfs/nfs4state.c | 1 + fs/nfs/pnfs.c | 2 ++ fs/nfsd/nfs4state.c | 1 + fs/nfsd/nfsctl.c | 1 + fs/reiserfs/namei.c | 1 + mm/mm_init.c | 1 + mm/vmscan.c | 1 + net/ax25/af_ax25.c | 1 + net/bridge/br_input.c | 1 + net/core/dev.c | 1 + net/decnet/dn_route.c | 2 +- net/ipv4/ah4.c | 1 + net/ipv4/esp4.c | 1 + net/ipv4/fib_semantics.c | 1 + net/ipv4/ip_vti.c | 1 + net/ipv4/ipcomp.c | 1 + net/ipv4/netfilter/ipt_REJECT.c | 1 + net/mac80211/cfg.c | 2 ++ net/netfilter/nf_conntrack_proto_dccp.c | 1 + net/netfilter/nf_tables_api.c | 1 + net/netfilter/nft_ct.c | 1 + net/netrom/nr_route.c | 4 ++++ net/packet/af_packet.c | 1 + net/rds/tcp_connect.c | 1 + net/rds/threads.c | 2 ++ net/rose/rose_route.c | 2 ++ net/rxrpc/af_rxrpc.c | 1 + net/sctp/input.c | 3 ++- net/sunrpc/rpc_pipe.c | 1 + net/sunrpc/xprtsock.c | 1 + net/tipc/link.c | 1 + net/wireless/nl80211.c | 1 + net/wireless/util.c | 1 + net/xfrm/xfrm_interface.c | 1 + security/integrity/ima/ima_main.c | 1 + security/integrity/ima/ima_policy.c | 2 ++ security/keys/process_keys.c | 1 + security/selinux/hooks.c | 1 + sound/drivers/pcsp/pcsp_input.c | 1 + sound/isa/sb/sb8_main.c | 1 + sound/pci/rme9652/hdspm.c | 1 + sound/soc/codecs/adav80x.c | 1 + sound/soc/codecs/arizona.c | 1 + sound/soc/codecs/cs42l52.c | 1 + sound/soc/codecs/cs42l56.c | 1 + sound/soc/codecs/cs47l92.c | 1 + sound/soc/codecs/wm8962.c | 1 + 209 files changed, 264 insertions(+), 26 deletions(-) -- 2.27.0 From gustavoars at kernel.org Fri Nov 20 18:27:37 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:27:37 -0600 Subject: [PATCH 023/141] staging: rtl8723bs: core: Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: In preparation to enable -Wimplicit-fallthrough for Clang, fix multiple warnings by explicitly adding multiple break statements instead of just letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva --- drivers/staging/rtl8723bs/core/rtw_cmd.c | 1 + drivers/staging/rtl8723bs/core/rtw_mlme_ext.c | 1 + drivers/staging/rtl8723bs/core/rtw_wlan_util.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/staging/rtl8723bs/core/rtw_cmd.c b/drivers/staging/rtl8723bs/core/rtw_cmd.c index 2abe205e3453..232661e6a5c9 100644 --- a/drivers/staging/rtl8723bs/core/rtw_cmd.c +++ b/drivers/staging/rtl8723bs/core/rtw_cmd.c @@ -1487,6 +1487,7 @@ void lps_ctrl_wk_hdl(struct adapter *padapter, u8 lps_ctrl_type) break; case LPS_CTRL_TRAFFIC_BUSY: LPS_Leave(padapter, "LPS_CTRL_TRAFFIC_BUSY"); + break; default: break; } diff --git a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c index b912ad2f4b72..ea44d653a591 100644 --- a/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723bs/core/rtw_mlme_ext.c @@ -1708,6 +1708,7 @@ unsigned int OnAssocRsp(struct adapter *padapter, union recv_frame *precv_frame) case _ERPINFO_IE_: ERP_IE_handler(padapter, pIE); + break; default: break; diff --git a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c index 372ce17c3569..2b13c683ba5c 100644 --- a/drivers/staging/rtl8723bs/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723bs/core/rtw_wlan_util.c @@ -1505,6 +1505,7 @@ unsigned int is_ap_in_tkip(struct adapter *padapter) case _RSN_IE_2_: if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER, 4)) return true; + break; default: break; -- 2.27.0 From gustavoars at kernel.org Fri Nov 20 18:27:44 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:27:44 -0600 Subject: [PATCH 024/141] staging: vt6655: Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <863fda60074850bc976974af48fa769c64725e64.1605896059.git.gustavoars@kernel.org> In preparation to enable -Wimplicit-fallthrough for Clang, fix multiple warnings by explicitly adding multiple break statements instead of just letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva --- drivers/staging/vt6655/device_main.c | 1 + drivers/staging/vt6655/rxtx.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 09ab6d6f2429..0adbd2b67df0 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -1579,6 +1579,7 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, case DISABLE_KEY: if (test_bit(key->hw_key_idx, &priv->key_entry_inuse)) clear_bit(key->hw_key_idx, &priv->key_entry_inuse); + break; default: break; } diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 477d19314634..1a64152de189 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -1004,6 +1004,7 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType, switch (info->control.hw_key->cipher) { case WLAN_CIPHER_SUITE_CCMP: cbMICHDR = sizeof(struct vnt_mic_hdr); + break; default: break; } @@ -1318,6 +1319,7 @@ int vnt_generate_fifo_header(struct vnt_private *priv, u32 dma_idx, break; case WLAN_CIPHER_SUITE_CCMP: tx_buffer_head->frag_ctl |= cpu_to_le16(FRAGCTL_AES); + break; default: break; } -- 2.27.0 From joe at perches.com Fri Nov 20 18:28:48 2020 From: joe at perches.com (Joe Perches) Date: Fri, 20 Nov 2020 10:28:48 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <3e0bbb1644fe53d79322c2feb28ccaf3e20c0e94.camel@perches.com> On Fri, 2020-11-20 at 12:21 -0600, Gustavo A. R. Silva wrote: > Hi all, > > This series aims to fix almost all remaining fall-through warnings in > order to enable -Wimplicit-fallthrough for Clang. > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > add multiple break/goto/return/fallthrough statements instead of just > letting the code fall through to the next case. > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > change[1] is meant to be reverted at some point. So, this patch helps > to move in that direction. This was a bit hard to parse for a second or three. Thanks Gustavo. How was this change done? From gustavoars at kernel.org Fri Nov 20 18:36:50 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:36:50 -0600 Subject: [PATCH 094/141] media: atomisp: Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <6a1c9b29a2d8e5accb48cd179cfe43b87fd83a00.1605896060.git.gustavoars@kernel.org> In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva --- drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c index b4813cd50daa..4a18da6bf0c1 100644 --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c @@ -368,6 +368,7 @@ static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor( break; case IA_CSS_CSI2_COMPRESSION_TYPE_2: predictor = MIPI_PREDICTOR_TYPE2 - 1; + break; default: break; } -- 2.27.0 From gustavoars at kernel.org Fri Nov 20 18:39:51 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:39:51 -0600 Subject: [PATCH 127/141] staging: qlge: Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <673bd9f27bcc2df8c9d12be94f54001d8066d4ab.1605896060.git.gustavoars@kernel.org> In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva --- drivers/staging/qlge/qlge_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c index 27da386f9d87..c41b1373dcf8 100644 --- a/drivers/staging/qlge/qlge_main.c +++ b/drivers/staging/qlge/qlge_main.c @@ -1385,6 +1385,7 @@ static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err, break; case IB_MAC_IOCB_RSP_ERR_CRC: stats->rx_crc_err++; + break; default: break; } -- 2.27.0 From gustavoars at kernel.org Fri Nov 20 18:39:57 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 12:39:57 -0600 Subject: [PATCH 128/141] staging: vt6656: Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <5a5a8f2489fbf61f65f0241c349737f7c9ad59ca.1605896060.git.gustavoars@kernel.org> In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a break statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva --- drivers/staging/vt6656/main_usb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index 8bf851c53f4e..b90d3dab28b1 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -914,6 +914,7 @@ static int vnt_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, vnt_mac_disable_keyentry(priv, key->hw_key_idx); } + break; default: break; -- 2.27.0 From kuba at kernel.org Fri Nov 20 18:53:44 2020 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 20 Nov 2020 10:53:44 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > This series aims to fix almost all remaining fall-through warnings in > order to enable -Wimplicit-fallthrough for Clang. > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > add multiple break/goto/return/fallthrough statements instead of just > letting the code fall through to the next case. > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > change[1] is meant to be reverted at some point. So, this patch helps > to move in that direction. > > Something important to mention is that there is currently a discrepancy > between GCC and Clang when dealing with switch fall-through to empty case > statements or to cases that only contain a break/continue/return > statement[2][3][4]. Are we sure we want to make this change? Was it discussed before? Are there any bugs Clangs puritanical definition of fallthrough helped find? IMVHO compiler warnings are supposed to warn about issues that could be bugs. Falling through to default: break; can hardly be a bug?! From gustavo at embeddedor.com Fri Nov 20 19:02:34 2020 From: gustavo at embeddedor.com (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 13:02:34 -0600 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <3e0bbb1644fe53d79322c2feb28ccaf3e20c0e94.camel@perches.com> References: <3e0bbb1644fe53d79322c2feb28ccaf3e20c0e94.camel@perches.com> Message-ID: <9f986394-125a-81f7-7696-fe1a9f4eb4f5@embeddedor.com> On 11/20/20 12:28, Joe Perches wrote: > On Fri, 2020-11-20 at 12:21 -0600, Gustavo A. R. Silva wrote: >> Hi all, >> >> This series aims to fix almost all remaining fall-through warnings in >> order to enable -Wimplicit-fallthrough for Clang. >> >> In preparation to enable -Wimplicit-fallthrough for Clang, explicitly >> add multiple break/goto/return/fallthrough statements instead of just >> letting the code fall through to the next case. >> >> Notice that in order to enable -Wimplicit-fallthrough for Clang, this >> change[1] is meant to be reverted at some point. So, this patch helps >> to move in that direction. > > This was a bit hard to parse for a second or three. > > Thanks Gustavo. > > How was this change done? I audited case by case in order to determine the best fit for each situation. Depending on the surrounding logic, sometimes it makes more sense a goto or a fallthrough rather than merely a break. Thanks -- Gustavo From gustavo at embeddedor.com Fri Nov 20 19:04:55 2020 From: gustavo at embeddedor.com (Gustavo A. R. Silva) Date: Fri, 20 Nov 2020 13:04:55 -0600 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: <4609d49b-4dd3-c017-b76e-a8a536871c05@embeddedor.com> Hi, On 11/20/20 12:53, Jakub Kicinski wrote: > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: >> This series aims to fix almost all remaining fall-through warnings in >> order to enable -Wimplicit-fallthrough for Clang. >> >> In preparation to enable -Wimplicit-fallthrough for Clang, explicitly >> add multiple break/goto/return/fallthrough statements instead of just >> letting the code fall through to the next case. >> >> Notice that in order to enable -Wimplicit-fallthrough for Clang, this >> change[1] is meant to be reverted at some point. So, this patch helps >> to move in that direction. >> >> Something important to mention is that there is currently a discrepancy >> between GCC and Clang when dealing with switch fall-through to empty case >> statements or to cases that only contain a break/continue/return >> statement[2][3][4]. > > Are we sure we want to make this change? Was it discussed before? > > Are there any bugs Clangs puritanical definition of fallthrough helped > find? > > IMVHO compiler warnings are supposed to warn about issues that could > be bugs. Falling through to default: break; can hardly be a bug?! The justification for this is explained in this same changelog text: Now that the -Wimplicit-fallthrough option has been globally enabled[5], any compiler should really warn on missing either a fallthrough annotation or any of the other case-terminating statements (break/continue/return/ goto) when falling through to the next case statement. Making exceptions to this introduces variation in case handling which may continue to lead to bugs, misunderstandings, and a general lack of robustness. The point of enabling options like -Wimplicit-fallthrough is to prevent human error and aid developers in spotting bugs before their code is even built/ submitted/committed, therefore eliminating classes of bugs. So, in order to really accomplish this, we should, and can, move in the direction of addressing any error-prone scenarios and get rid of the unintentional fallthrough bug-class in the kernel, entirely, even if there is some minor redundancy. Better to have explicit case-ending statements than continue to have exceptions where one must guess as to the right result. The compiler will eliminate any actual redundancy. Note that there is already a patch in mainline that addresses almost 40,000 of these issues[6]. [1] commit e2079e93f562c ("kbuild: Do not enable -Wimplicit-fallthrough for clang for now") [2] ClangBuiltLinux#636 [3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91432 [4] https://godbolt.org/z/xgkvIh [5] commit a035d552a93b ("Makefile: Globally enable fall-through warning") [6] commit 4169e889e588 ("include: jhash/signal: Fix fall-through warnings for Clang") Thanks -- Gustavo From keescook at chromium.org Fri Nov 20 19:30:40 2020 From: keescook at chromium.org (Kees Cook) Date: Fri, 20 Nov 2020 11:30:40 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: <202011201129.B13FDB3C@keescook> On Fri, Nov 20, 2020 at 10:53:44AM -0800, Jakub Kicinski wrote: > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > > This series aims to fix almost all remaining fall-through warnings in > > order to enable -Wimplicit-fallthrough for Clang. > > > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > > add multiple break/goto/return/fallthrough statements instead of just > > letting the code fall through to the next case. > > > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > > change[1] is meant to be reverted at some point. So, this patch helps > > to move in that direction. > > > > Something important to mention is that there is currently a discrepancy > > between GCC and Clang when dealing with switch fall-through to empty case > > statements or to cases that only contain a break/continue/return > > statement[2][3][4]. > > Are we sure we want to make this change? Was it discussed before? > > Are there any bugs Clangs puritanical definition of fallthrough helped > find? > > IMVHO compiler warnings are supposed to warn about issues that could > be bugs. Falling through to default: break; can hardly be a bug?! It's certainly a place where the intent is not always clear. I think this makes all the cases unambiguous, and doesn't impact the machine code, since the compiler will happily optimize away any behavioral redundancy. -- Kees Cook From kuba at kernel.org Fri Nov 20 19:51:42 2020 From: kuba at kernel.org (Jakub Kicinski) Date: Fri, 20 Nov 2020 11:51:42 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <202011201129.B13FDB3C@keescook> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> Message-ID: <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> On Fri, 20 Nov 2020 11:30:40 -0800 Kees Cook wrote: > On Fri, Nov 20, 2020 at 10:53:44AM -0800, Jakub Kicinski wrote: > > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > > > This series aims to fix almost all remaining fall-through warnings in > > > order to enable -Wimplicit-fallthrough for Clang. > > > > > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > > > add multiple break/goto/return/fallthrough statements instead of just > > > letting the code fall through to the next case. > > > > > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > > > change[1] is meant to be reverted at some point. So, this patch helps > > > to move in that direction. > > > > > > Something important to mention is that there is currently a discrepancy > > > between GCC and Clang when dealing with switch fall-through to empty case > > > statements or to cases that only contain a break/continue/return > > > statement[2][3][4]. > > > > Are we sure we want to make this change? Was it discussed before? > > > > Are there any bugs Clangs puritanical definition of fallthrough helped > > find? > > > > IMVHO compiler warnings are supposed to warn about issues that could > > be bugs. Falling through to default: break; can hardly be a bug?! > > It's certainly a place where the intent is not always clear. I think > this makes all the cases unambiguous, and doesn't impact the machine > code, since the compiler will happily optimize away any behavioral > redundancy. If none of the 140 patches here fix a real bug, and there is no change to machine code then it sounds to me like a W=2 kind of a warning. I think clang is just being annoying here, but if I'm the only one who feels this way chances are I'm wrong :) From keescook at chromium.org Fri Nov 20 20:48:01 2020 From: keescook at chromium.org (Kees Cook) Date: Fri, 20 Nov 2020 12:48:01 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: <202011201244.78E002D5@keescook> On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > On Fri, 20 Nov 2020 11:30:40 -0800 Kees Cook wrote: > > On Fri, Nov 20, 2020 at 10:53:44AM -0800, Jakub Kicinski wrote: > > > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > > > > This series aims to fix almost all remaining fall-through warnings in > > > > order to enable -Wimplicit-fallthrough for Clang. > > > > > > > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > > > > add multiple break/goto/return/fallthrough statements instead of just > > > > letting the code fall through to the next case. > > > > > > > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > > > > change[1] is meant to be reverted at some point. So, this patch helps > > > > to move in that direction. > > > > > > > > Something important to mention is that there is currently a discrepancy > > > > between GCC and Clang when dealing with switch fall-through to empty case > > > > statements or to cases that only contain a break/continue/return > > > > statement[2][3][4]. > > > > > > Are we sure we want to make this change? Was it discussed before? > > > > > > Are there any bugs Clangs puritanical definition of fallthrough helped > > > find? > > > > > > IMVHO compiler warnings are supposed to warn about issues that could > > > be bugs. Falling through to default: break; can hardly be a bug?! > > > > It's certainly a place where the intent is not always clear. I think > > this makes all the cases unambiguous, and doesn't impact the machine > > code, since the compiler will happily optimize away any behavioral > > redundancy. > > If none of the 140 patches here fix a real bug, and there is no change > to machine code then it sounds to me like a W=2 kind of a warning. I'd like to avoid splitting common -W options between default and W=2 just based on the compiler. Getting -Wimplicit-fallthrough enabled found plenty of bugs, so making sure it works correctly for both compilers feels justified to me. (This is just a subset of the same C language short-coming.) > I think clang is just being annoying here, but if I'm the only one who > feels this way chances are I'm wrong :) It's being pretty pedantic, but I don't think it's unreasonable to explicitly state how every case ends. GCC's silence for the case of "fall through to a break" doesn't really seem justified. -- Kees Cook From financialcapability6 at gmail.com Fri Nov 20 18:36:57 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Fri, 20 Nov 2020 10:36:57 -0800 Subject: Corporate and Personal Loan ,t Message-ID: <20201120210027.5810587639@hemlock.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From miguel.ojeda.sandonis at gmail.com Fri Nov 20 22:21:17 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Fri, 20 Nov 2020 23:21:17 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: Hi Gustavo, On Fri, Nov 20, 2020 at 7:21 PM Gustavo A. R. Silva wrote: > > Hi all, > > This series aims to fix almost all remaining fall-through warnings in > order to enable -Wimplicit-fallthrough for Clang. Thanks for this. Since this warning is reliable in both/all compilers and we are eventually getting rid of all the cases, what about going even further and making it an error right after? Cheers, Miguel From tkjos at google.com Fri Nov 20 23:37:43 2020 From: tkjos at google.com (Todd Kjos) Date: Fri, 20 Nov 2020 15:37:43 -0800 Subject: [PATCH] binder: add flag to clear buffer on txn complete Message-ID: <20201120233743.3617529-1-tkjos@google.com> Add a per-transaction flag to indicate that the buffer must be cleared when the transaction is complete to prevent copies of sensitive data from being preserved in memory. Signed-off-by: Todd Kjos --- drivers/android/binder.c | 1 + drivers/android/binder_alloc.c | 48 +++++++++++++++++++++++++++++ drivers/android/binder_alloc.h | 4 ++- include/uapi/linux/android/binder.h | 1 + 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index b5117576792b..2a3952925855 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -3146,6 +3146,7 @@ static void binder_transaction(struct binder_proc *proc, t->buffer->debug_id = t->debug_id; t->buffer->transaction = t; t->buffer->target_node = target_node; + t->buffer->clear_on_free = !!(t->flags & TF_CLEAR_BUF); trace_binder_transaction_alloc_buf(t->buffer); if (binder_alloc_copy_user_to_buffer( diff --git a/drivers/android/binder_alloc.c b/drivers/android/binder_alloc.c index 2f846b7ae8b8..7caf74ad2405 100644 --- a/drivers/android/binder_alloc.c +++ b/drivers/android/binder_alloc.c @@ -696,6 +696,8 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, binder_insert_free_buffer(alloc, buffer); } +static void binder_alloc_clear_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer); /** * binder_alloc_free_buf() - free a binder buffer * @alloc: binder_alloc for this proc @@ -706,6 +708,18 @@ static void binder_free_buf_locked(struct binder_alloc *alloc, void binder_alloc_free_buf(struct binder_alloc *alloc, struct binder_buffer *buffer) { + /* + * We could eliminate the call to binder_alloc_clear_buf() + * from binder_alloc_deferred_release() by moving this to + * binder_alloc_free_buf_locked(). However, that could + * increase contention for the alloc mutex if clear_on_free + * is used frequently for large buffers. The mutex is not + * needed for correctness here. + */ + if (buffer->clear_on_free) { + binder_alloc_clear_buf(alloc, buffer); + buffer->clear_on_free = false; + } mutex_lock(&alloc->mutex); binder_free_buf_locked(alloc, buffer); mutex_unlock(&alloc->mutex); @@ -802,6 +816,10 @@ void binder_alloc_deferred_release(struct binder_alloc *alloc) /* Transaction should already have been freed */ BUG_ON(buffer->transaction); + if (buffer->clear_on_free) { + binder_alloc_clear_buf(alloc, buffer); + buffer->clear_on_free = false; + } binder_free_buf_locked(alloc, buffer); buffers++; } @@ -1135,6 +1153,36 @@ static struct page *binder_alloc_get_page(struct binder_alloc *alloc, return lru_page->page_ptr; } +/** + * binder_alloc_clear_buf() - zero out buffer + * @alloc: binder_alloc for this proc + * @buffer: binder buffer to be cleared + * + * memset the given buffer to 0 + */ +static void binder_alloc_clear_buf(struct binder_alloc *alloc, + struct binder_buffer *buffer) +{ + size_t bytes = binder_alloc_buffer_size(alloc, buffer); + binder_size_t buffer_offset = 0; + + while (bytes) { + unsigned long size; + struct page *page; + pgoff_t pgoff; + void *kptr; + + page = binder_alloc_get_page(alloc, buffer, + buffer_offset, &pgoff); + size = min_t(size_t, bytes, PAGE_SIZE - pgoff); + kptr = kmap(page) + pgoff; + memset(kptr, 0, size); + kunmap(page); + bytes -= size; + buffer_offset += size; + } +} + /** * binder_alloc_copy_user_to_buffer() - copy src user to tgt user * @alloc: binder_alloc for this proc diff --git a/drivers/android/binder_alloc.h b/drivers/android/binder_alloc.h index 55d8b4106766..6e8e001381af 100644 --- a/drivers/android/binder_alloc.h +++ b/drivers/android/binder_alloc.h @@ -23,6 +23,7 @@ struct binder_transaction; * @entry: entry alloc->buffers * @rb_node: node for allocated_buffers/free_buffers rb trees * @free: %true if buffer is free + * @clear_on_free: %true if buffer must be zeroed after use * @allow_user_free: %true if user is allowed to free buffer * @async_transaction: %true if buffer is in use for an async txn * @debug_id: unique ID for debugging @@ -41,9 +42,10 @@ struct binder_buffer { struct rb_node rb_node; /* free entry by size or allocated entry */ /* by address */ unsigned free:1; + unsigned clear_on_free:1; unsigned allow_user_free:1; unsigned async_transaction:1; - unsigned debug_id:29; + unsigned debug_id:28; struct binder_transaction *transaction; diff --git a/include/uapi/linux/android/binder.h b/include/uapi/linux/android/binder.h index f1ce2c4c077e..ec84ad106568 100644 --- a/include/uapi/linux/android/binder.h +++ b/include/uapi/linux/android/binder.h @@ -248,6 +248,7 @@ enum transaction_flags { TF_ROOT_OBJECT = 0x04, /* contents are the component's root object */ TF_STATUS_CODE = 0x08, /* contents are a 32-bit status code */ TF_ACCEPT_FDS = 0x10, /* allow replies with file descriptors */ + TF_CLEAR_BUF = 0x20, /* clear buffer on txn complete */ }; struct binder_transaction_data { -- 2.29.2.454.gaff20da3a2-goog From gregkh at linuxfoundation.org Sat Nov 21 07:14:09 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Sat, 21 Nov 2020 08:14:09 +0100 Subject: [PATCH] binder: add flag to clear buffer on txn complete In-Reply-To: <20201120233743.3617529-1-tkjos@google.com> References: <20201120233743.3617529-1-tkjos@google.com> Message-ID: On Fri, Nov 20, 2020 at 03:37:43PM -0800, Todd Kjos wrote: > Add a per-transaction flag to indicate that the buffer > must be cleared when the transaction is complete to > prevent copies of sensitive data from being preserved > in memory. > > Signed-off-by: Todd Kjos > --- DOes this need to be backported to stable kernels as well? thanks, greg k-h From financialcapability6 at gmail.com Fri Nov 20 07:45:35 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Thu, 19 Nov 2020 23:45:35 -0800 Subject: Corporate and Personal Loan ,t Message-ID: <20201121080041.6590686E7A@fraxinus.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From vkoul at kernel.org Sat Nov 21 12:10:39 2020 From: vkoul at kernel.org (Vinod Koul) Date: Sat, 21 Nov 2020 17:40:39 +0530 Subject: [PATCH v5 0/4] MT7621 PCIe PHY In-Reply-To: References: <20201119154337.9195-1-sergio.paracuellos@gmail.com> Message-ID: <20201121121039.GA8403@vkoul-mobl> On 20-11-20, 17:20, Sergio Paracuellos wrote: > Hi Vinod, > > On Thu, Nov 19, 2020 at 4:43 PM Sergio Paracuellos > wrote: > > > > This series adds support for the PCIe PHY found in the Mediatek > > MT7621 SoC. > > > > There is also a 'mt7621-pci' driver which is the controller part > > which is still in staging and is a client of this phy. > > > > Both drivers have been tested together in a gnubee1 board. > > > > This series are rebased on the top of linux-next: > > commit 4e78c578cb98 ("Add linux-next specific files for 20201030") > > > > Changes in v5: > > - PATCH 1/4: Recollect Rob's Reviewed-by of bindings. > > - PATCH 4/4: Recollect Greg's Acked-by for removing stuff from > > staging area. > > - Make Vinod's review comments changes in [0]: > > * Use FIELD_GET and FIELD_PREP apis and avoid multiple *_VAL and > > *_SHIFT custom definitions. > > * Remove phy-read and phy-write internal functions and directly > > call regmap_read and regmap_write in 'mt7621_phy_rmw'. > > * Change some traces from info to debug log level. > > * Note that I have maintained 'mt7621_phy_rmw' instead of use > > 'regmap_update_bits'. This is because in order to get a reliable > > boot registers must be written event the contained value in > > that register is the same. I have preferred doing in this way > > instead of using 'regmap_update_bits_base' passing 'false' for > > async and 'true' for the force write. If this way of using > > 'regmap_update_bits_base' is preferred just let me know. > > I notice we already have 'regmap_write_bits' function. I will use this > and avoid mt7621_phy_rmw > and send v6 of this series. > > Also, do you have any preference of where you want this series to be rebased on? Phy-next please -- ~Vinod From xiakaixu1987 at gmail.com Sat Nov 21 12:17:21 2020 From: xiakaixu1987 at gmail.com (xiakaixu1987 at gmail.com) Date: Sat, 21 Nov 2020 20:17:21 +0800 Subject: [PATCH] staging: rtl8723bs: remove redundant statements Message-ID: <1605961041-12875-1-git-send-email-kaixuxia@tencent.com> From: Kaixu Xia The bool variable is2T is true, so the if statement is redundant. we can directly set the variable bound to 8 and remove the if statement. Reported-by: Tosk Robot Signed-off-by: Kaixu Xia --- drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c index 85ea535dd6e9..645f4f2a835e 100644 --- a/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c +++ b/drivers/staging/rtl8723bs/hal/HalPhyRf_8723B.c @@ -1407,14 +1407,9 @@ static bool phy_SimularityCompare_8723B( u32 i, j, diff, SimularityBitMap, bound = 0; u8 final_candidate[2] = {0xFF, 0xFF}; /* for path A and path B */ bool bResult = true; - bool is2T = true; s32 tmp1 = 0, tmp2 = 0; - if (is2T) - bound = 8; - else - bound = 4; - + bound = 8; SimularityBitMap = 0; for (i = 0; i < bound; i++) { -- 2.20.0 From robh at kernel.org Sat Nov 21 13:30:50 2020 From: robh at kernel.org (Rob Herring) Date: Sat, 21 Nov 2020 07:30:50 -0600 Subject: [PATCH v3 1/5] dt-bindings: clock: add dt binding header for mt7621 clocks In-Reply-To: <20201113154632.24973-2-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-2-sergio.paracuellos@gmail.com> Message-ID: <20201121133050.GA2129481@robh.at.kernel.org> On Fri, 13 Nov 2020 16:46:28 +0100, Sergio Paracuellos wrote: > Adds dt binding header for 'mediatek,mt7621-clk' clocks. > > Signed-off-by: Sergio Paracuellos > --- > include/dt-bindings/clock/mt7621-clk.h | 41 ++++++++++++++++++++++++++ > 1 file changed, 41 insertions(+) > create mode 100644 include/dt-bindings/clock/mt7621-clk.h > Acked-by: Rob Herring From robh at kernel.org Sat Nov 21 13:34:32 2020 From: robh at kernel.org (Rob Herring) Date: Sat, 21 Nov 2020 07:34:32 -0600 Subject: [PATCH v3 2/5] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201113154632.24973-3-sergio.paracuellos@gmail.com> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-3-sergio.paracuellos@gmail.com> Message-ID: <20201121133432.GA2130098@robh.at.kernel.org> On Fri, Nov 13, 2020 at 04:46:29PM +0100, Sergio Paracuellos wrote: > Adds device tree binding documentation for clocks in the > MT7621 SOC. > > Signed-off-by: Sergio Paracuellos > --- > .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++++++++++++++++++ > 1 file changed, 61 insertions(+) > create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > new file mode 100644 > index 000000000000..363bd9880e29 > --- /dev/null > +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > @@ -0,0 +1,61 @@ > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > +%YAML 1.2 > +--- > +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# > +$schema: http://devicetree.org/meta-schemas/core.yaml# > + > +title: MT7621 Clock Device Tree Bindings > + > +maintainers: > + - Sergio Paracuellos > + > +description: | > + The MT7621 has a PLL controller from where the cpu clock is provided > + as well as derived clocks for the bus and the peripherals. It also > + can gate SoC device clocks. > + > + Each clock is assigned an identifier and client nodes use this identifier > + to specify the clock which they consume. > + > + All these identifiers could be found in: > + [1]: . > + > +properties: > + compatible: > + const: mediatek,mt7621-clk > + > + ralink,sysctl: > + $ref: /schemas/types.yaml#/definitions/phandle > + description: > + phandle to the syscon which is in the same address area with syscon > + device. > + > + "#clock-cells": > + description: > + The first cell indicates the clock gate number, see [1] for available > + clocks. > + const: 1 > + > + clock-output-names: > + maxItems: 8 > + > +required: > + - compatible > + - ralink,sysctl > + - '#clock-cells' > + - clock-output-names > + > +additionalProperties: false > + > +examples: > + - | > + #include > + > + pll { > + compatible = "mediatek,mt7621-clk"; > + ralink,sysctl = <&sysc>; If this is the only control interface, then make this a child of 'sysc'. And use 'reg' if there's a dedicated range of registers. > + #clock-cells = <1>; > + clock-output-names = "xtal", "cpu", "bus", > + "50m", "125m", "150m", > + "250m", "270m"; > + }; > -- > 2.25.1 > From sergio.paracuellos at gmail.com Sat Nov 21 14:50:23 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 15:50:23 +0100 Subject: [PATCH v3 2/5] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201121133432.GA2130098@robh.at.kernel.org> References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-3-sergio.paracuellos@gmail.com> <20201121133432.GA2130098@robh.at.kernel.org> Message-ID: Hi Rob, Thanks for the review. On Sat, Nov 21, 2020 at 2:34 PM Rob Herring wrote: > > On Fri, Nov 13, 2020 at 04:46:29PM +0100, Sergio Paracuellos wrote: > > Adds device tree binding documentation for clocks in the > > MT7621 SOC. > > > > Signed-off-by: Sergio Paracuellos > > --- > > .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++++++++++++++++++ > > 1 file changed, 61 insertions(+) > > create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > > > diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > new file mode 100644 > > index 000000000000..363bd9880e29 > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > @@ -0,0 +1,61 @@ > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > > +%YAML 1.2 > > +--- > > +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > + > > +title: MT7621 Clock Device Tree Bindings > > + > > +maintainers: > > + - Sergio Paracuellos > > + > > +description: | > > + The MT7621 has a PLL controller from where the cpu clock is provided > > + as well as derived clocks for the bus and the peripherals. It also > > + can gate SoC device clocks. > > + > > + Each clock is assigned an identifier and client nodes use this identifier > > + to specify the clock which they consume. > > + > > + All these identifiers could be found in: > > + [1]: . > > + > > +properties: > > + compatible: > > + const: mediatek,mt7621-clk > > + > > + ralink,sysctl: > > + $ref: /schemas/types.yaml#/definitions/phandle > > + description: > > + phandle to the syscon which is in the same address area with syscon > > + device. > > + > > + "#clock-cells": > > + description: > > + The first cell indicates the clock gate number, see [1] for available > > + clocks. > > + const: 1 > > + > > + clock-output-names: > > + maxItems: 8 > > + > > +required: > > + - compatible > > + - ralink,sysctl > > + - '#clock-cells' > > + - clock-output-names > > + > > +additionalProperties: false > > + > > +examples: > > + - | > > + #include > > + > > + pll { > > + compatible = "mediatek,mt7621-clk"; > > + ralink,sysctl = <&sysc>; > > If this is the only control interface, then make this a child of 'sysc'. > And use 'reg' if there's a dedicated range of registers. This is the only one now in the device tree which is still in staging but there are several places where this sys control registers are accessed from. In the case of the clocks we need: #define SYSC_REG_SYSTEM_CONFIG0 0x10 #define SYSC_REG_SYSTEM_CONFIG1 0x14 #define SYSC_REG_CLKCFG0 0x2c #define SYSC_REG_CLKCFG1 0x30 #define SYSC_REG_CUR_CLK_STS 0x44 where there is not a range as it is but several different registers from where we need to read or write things. I wrote the driver using syscon and regmap because I thought in that way it might be more maintainable but this architecture also has operations to read and write registers from sysc and not using regmap at all. This operations are defined in arch/mips/include/asm/mach-ralink/ralink_regs.h. But because this sysc is currently mapped I cannot request its registers using reg in the device tree. If you prefer me to avoid the use of this syscon and regmap and use operations defined in ralink_regs.h, this will become in a node without "regs" or "ralink,sysctl" property: pll { compatible = "mediatek,mt7621-clk"; #clock-cells = <1>; clock-output-names = "xtal", "cpu", "bus", "50m", "125m", "150m", "250m", "270m"; }; What should I do then? Best regards, Sergio Paracuellos > > > + #clock-cells = <1>; > > + clock-output-names = "xtal", "cpu", "bus", > > + "50m", "125m", "150m", > > + "250m", "270m"; > > + }; > > -- > > 2.25.1 > > From sergio.paracuellos at gmail.com Sat Nov 21 15:50:34 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 16:50:34 +0100 Subject: [PATCH v6 1/4] dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> Message-ID: <20201121155037.21354-2-sergio.paracuellos@gmail.com> Add bindings to describe Mediatek MT7621 PCIe PHY. Signed-off-by: Sergio Paracuellos Reviewed-by: Rob Herring --- .../bindings/phy/mediatek,mt7621-pci-phy.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml new file mode 100644 index 000000000000..0ccaded3f245 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: (GPL-2.0-only or BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek Mt7621 PCIe PHY Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +properties: + compatible: + const: mediatek,mt7621-pci-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 1 + description: selects if the phy is dual-ported + +required: + - compatible + - reg + - "#phy-cells" + +additionalProperties: false + +examples: + - | + pcie0_phy: pcie-phy at 1e149000 { + compatible = "mediatek,mt7621-pci-phy"; + reg = <0x1e149000 0x0700>; + #phy-cells = <1>; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Sat Nov 21 15:50:33 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 16:50:33 +0100 Subject: [PATCH v6 0/4] MT7621 PCIe PHY Message-ID: <20201121155037.21354-1-sergio.paracuellos@gmail.com> This series adds support for the PCIe PHY found in the Mediatek MT7621 SoC. There is also a 'mt7621-pci' driver which is the controller part which is still in staging and is a client of this phy. Both drivers have been tested together in a gnubee1 board. This series are rebased on the top of linux-phy: commit 768a711e2d4b ("phy: samsung: phy-exynos-pcie: fix typo 'tunning'") Changes in v6: - Change definition name to XTAL_MASK to fix its use in one line. - Fix XTAL_MASK mask value after use it with 'FIELD_GET'. - Add comment in 'mt7621_phy_rmw' about why 'regmap_write_bits' cannot be used. - Rebase series on the top of 'next' branch of 'linux-phy' tree. Changes in v5: - PATCH 1/4: Recollect Rob's Reviewed-by of bindings. - PATCH 4/4: Recollect Greg's Acked-by for removing stuff from staging area. - Use 'devm_platform_ioremap_resource' instead of using 'platform_get_resource' and 'devm_ioremap_resource'. - Make Vinod's review comments changes in [0]: * Use FIELD_GET and FIELD_PREP apis and avoid multiple *_VAL and *_SHIFT custom definitions. * Remove phy-read and phy-write internal functions and directly call regmap_read and regmap_write in 'mt7621_phy_rmw'. * Change some traces from info to debug log level. * Note that I have maintained 'mt7621_phy_rmw' instead of use 'regmap_update_bits'. This is because in order to get a reliable boot registers must be written event the contained value in that register is the same. I have preferred doing in this way instead of using 'regmap_update_bits_base' passing 'false' for async and 'true' for the force write. If this way of using 'regmap_update_bits_base' is preferred just let me know. Changes in v4: - Bindings moved from txt to yaml so previous Rob's Reviewed-by is not in the new patch with the yaml file. - 'phy-cells' property means now if phy is dual-ported. - Avoid custom 'xlate' function and properly set registers when the phy is dual ported. - Add use of 'builtin_platform_driver'. - Added a patch including myself as maintainer in the MAINTAINERS file. - Add a patch removing patch from staging to make easier the complete inclusion and avoid possible problems might appear in 'linux-next' if the series are included. Changes in v3: - Recollect Rob's Reviewed-by of bindings. - Make Kishon Vijay suggested changes in v2: (See https://lkml.org/lkml/2019/4/17/53) - Kconfig: * Add depends on COMPILE_TEST * Select REGMAP_MMIO - Make use of 'soc_device_attribute' and 'soc_device_match' - Use regmap mmio API instead of directly 'readl' and 'writel'. - Use 'platform_get_resource' instead of 'of_address_to_resource'. Changes in v2: - Reorder patches to get bindings first in the series. - Don't use child nodes in the device tree. Use #phy-cells=1 instead. - Update driver code with new 'xlate' function for the new device tree. - Minor changes in driver's macros changing some spaces to tabs. Thanks in advance for your time. Best regards, Sergio Paracuellos [0]: http://driverdev.linuxdriverproject.org/pipermail/driverdev-devel/2020-November/148864.html Sergio Paracuellos (4): dt-bindings: phy: Add binding for Mediatek MT7621 PCIe PHY phy: ralink: Add PHY driver for MT7621 PCIe PHY MAINTAINERS: add MT7621 PHY PCI maintainer staging: mt7621-pci-phy: remove driver from staging .../phy}/mediatek,mt7621-pci-phy.yaml | 2 +- MAINTAINERS | 6 + drivers/phy/ralink/Kconfig | 8 ++ drivers/phy/ralink/Makefile | 1 + .../ralink/phy-mt7621-pci.c} | 115 +++++++----------- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/mt7621-pci-phy/Kconfig | 8 -- drivers/staging/mt7621-pci-phy/Makefile | 2 - drivers/staging/mt7621-pci-phy/TODO | 4 - 10 files changed, 63 insertions(+), 86 deletions(-) rename {drivers/staging/mt7621-pci-phy => Documentation/devicetree/bindings/phy}/mediatek,mt7621-pci-phy.yaml (92%) rename drivers/{staging/mt7621-pci-phy/pci-mt7621-phy.c => phy/ralink/phy-mt7621-pci.c} (76%) delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile delete mode 100644 drivers/staging/mt7621-pci-phy/TODO -- 2.25.1 From sergio.paracuellos at gmail.com Sat Nov 21 15:50:35 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 16:50:35 +0100 Subject: [PATCH v6 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> Message-ID: <20201121155037.21354-3-sergio.paracuellos@gmail.com> This patch adds a driver for the PCIe PHY of MT7621 SoC. Signed-off-by: Sergio Paracuellos --- drivers/phy/ralink/Kconfig | 8 + drivers/phy/ralink/Makefile | 1 + drivers/phy/ralink/phy-mt7621-pci.c | 352 ++++++++++++++++++++++++++++ 3 files changed, 361 insertions(+) create mode 100644 drivers/phy/ralink/phy-mt7621-pci.c diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig index da982c9cffb3..2fabb14d2998 100644 --- a/drivers/phy/ralink/Kconfig +++ b/drivers/phy/ralink/Kconfig @@ -2,6 +2,14 @@ # # PHY drivers for Ralink platforms. # +config PHY_MT7621_PCI + tristate "MediaTek MT7621 PCI PHY Driver" + depends on (RALINK || COMPILE_TEST) && OF + select GENERIC_PHY + select REGMAP_MMIO + help + Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, + config PHY_RALINK_USB tristate "Ralink USB PHY driver" depends on RALINK || COMPILE_TEST diff --git a/drivers/phy/ralink/Makefile b/drivers/phy/ralink/Makefile index d8d3ffcf0a15..cda2a4a7ca5e 100644 --- a/drivers/phy/ralink/Makefile +++ b/drivers/phy/ralink/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_PHY_MT7621_PCI) += phy-mt7621-pci.o obj-$(CONFIG_PHY_RALINK_USB) += phy-ralink-usb.o diff --git a/drivers/phy/ralink/phy-mt7621-pci.c b/drivers/phy/ralink/phy-mt7621-pci.c new file mode 100644 index 000000000000..db79088d5362 --- /dev/null +++ b/drivers/phy/ralink/phy-mt7621-pci.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mediatek MT7621 PCI PHY Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define RG_PE1_PIPE_REG 0x02c +#define RG_PE1_PIPE_RST BIT(12) +#define RG_PE1_PIPE_CMD_FRC BIT(4) + +#define RG_P0_TO_P1_WIDTH 0x100 +#define RG_PE1_H_LCDDS_REG 0x49c +#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) + +#define RG_PE1_FRC_H_XTAL_REG 0x400 +#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) +#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) + +#define RG_PE1_FRC_PHY_REG 0x000 +#define RG_PE1_FRC_PHY_EN BIT(4) +#define RG_PE1_PHY_EN BIT(5) + +#define RG_PE1_H_PLL_REG 0x490 +#define RG_PE1_H_PLL_BC GENMASK(23, 22) +#define RG_PE1_H_PLL_BP GENMASK(21, 18) +#define RG_PE1_H_PLL_IR GENMASK(15, 12) +#define RG_PE1_H_PLL_IC GENMASK(11, 8) +#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) +#define RG_PE1_PLL_DIVEN GENMASK(3, 1) + +#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc +#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) + +#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 +#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) + +#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 +#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) +#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) + +#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 +#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) + +#define RG_PE1_H_PLL_BR_REG 0x4ac +#define RG_PE1_H_PLL_BR GENMASK(18, 16) + +#define RG_PE1_MSTCKDIV_REG 0x414 +#define RG_PE1_MSTCKDIV GENMASK(7, 6) + +#define RG_PE1_FRC_MSTCKDIV BIT(5) + +#define XTAL_MASK GENMASK(7, 6) + +#define MAX_PHYS 2 + +/** + * struct mt7621_pci_phy - Mt7621 Pcie PHY core + * @dev: pointer to device + * @regmap: kernel regmap pointer + * @phy: pointer to the kernel PHY device + * @port_base: base register + * @has_dual_port: if the phy has dual ports. + * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst' + * needs to be executed. Depends on chip revision. + */ +struct mt7621_pci_phy { + struct device *dev; + struct regmap *regmap; + struct phy *phy; + void __iomem *port_base; + bool has_dual_port; + bool bypass_pipe_rst; +}; + +static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, + u32 reg, u32 clr, u32 set) +{ + u32 val; + + /* + * We cannot use 'regmap_write_bits' here because internally + * 'set' is masked before is set to the value that will be + * written to the register. That way results in no reliable + * pci setup. Avoid to mask 'set' before set value to 'val' + * completely avoid the problem. + */ + regmap_read(phy->regmap, reg, &val); + val &= ~clr; + val |= set; + regmap_write(phy->regmap, reg, val); +} + +static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy) +{ + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_RST); + mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, + 0, RG_PE1_PIPE_CMD_FRC); + } +} + +static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) +{ + struct device *dev = phy->dev; + u32 xtal_mode; + + xtal_mode = FIELD_GET(XTAL_MASK, rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0)); + + /* Set PCIe Port PHY to disable SSC */ + /* Debug Xtal Type */ + mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, + RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, + RG_PE1_FRC_H_XTAL_TYPE | + FIELD_PREP(RG_PE1_H_XTAL_TYPE, 0x00)); + + /* disable port */ + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, RG_PE1_PHY_EN, + RG_PE1_FRC_PHY_EN); + + if (phy->has_dual_port) { + mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* Set Pre-divider ratio (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x01)); + + dev_dbg(dev, "Xtal is 40MHz\n"); + } else if (xtal_mode >= 6) { /* 25MHz Xal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + /* Select feedback clock */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, + RG_PE1_H_PLL_FBKSEL, + FIELD_PREP(RG_PE1_H_PLL_FBKSEL, 0x01)); + + /* DDS NCPO PCW (for host mode) */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x00)); + + /* DDS SSC dither period control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, + RG_PE1_H_LCDDS_SSC_PRD, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_PRD, 0x18d)); + + /* DDS SSC dither amplitude control */ + mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, + RG_PE1_H_LCDDS_SSC_DELTA | + RG_PE1_H_LCDDS_SSC_DELTA1, + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA, 0x4a) | + FIELD_PREP(RG_PE1_H_LCDDS_SSC_DELTA1, 0x4a)); + + dev_dbg(dev, "Xtal is 25MHz\n"); + } else { /* 20MHz Xtal */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, RG_PE1_H_PLL_PREDIV, + FIELD_PREP(RG_PE1_H_PLL_PREDIV, 0x00)); + + dev_dbg(dev, "Xtal is 20MHz\n"); + } + + /* DDS clock inversion */ + mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG, + RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV); + + /* Set PLL bits */ + mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, + RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | + RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN, + FIELD_PREP(RG_PE1_H_PLL_BC, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_BP, 0x06) | + FIELD_PREP(RG_PE1_H_PLL_IR, 0x02) | + FIELD_PREP(RG_PE1_H_PLL_IC, 0x01) | + FIELD_PREP(RG_PE1_PLL_DIVEN, 0x02)); + + mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, RG_PE1_H_PLL_BR, + FIELD_PREP(RG_PE1_H_PLL_BR, 0x00)); + + if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ + /* set force mode enable of da_pe1_mstckdiv */ + mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG, + RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV, + FIELD_PREP(RG_PE1_MSTCKDIV, 0x01) | + RG_PE1_FRC_MSTCKDIV); + } +} + +static int mt7621_pci_phy_init(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + if (mphy->bypass_pipe_rst) + mt7621_bypass_pipe_rst(mphy); + + mt7621_set_phy_for_ssc(mphy); + + return 0; +} + +static int mt7621_pci_phy_power_on(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Enable PHY and disable force mode */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_power_off(struct phy *phy) +{ + struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); + + /* Disable PHY */ + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + + if (mphy->has_dual_port) { + mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, + RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); + } + + return 0; +} + +static int mt7621_pci_phy_exit(struct phy *phy) +{ + return 0; +} + +static const struct phy_ops mt7621_pci_phy_ops = { + .init = mt7621_pci_phy_init, + .exit = mt7621_pci_phy_exit, + .power_on = mt7621_pci_phy_power_on, + .power_off = mt7621_pci_phy_power_off, + .owner = THIS_MODULE, +}; + +static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, + struct of_phandle_args *args) +{ + struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); + + if (WARN_ON(args->args[0] >= MAX_PHYS)) + return ERR_PTR(-ENODEV); + + mt7621_phy->has_dual_port = args->args[0]; + + dev_info(dev, "PHY for 0x%08x (dual port = %d)\n", + (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port); + + return mt7621_phy->phy; +} + +static const struct soc_device_attribute mt7621_pci_quirks_match[] = { + { .soc_id = "mt7621", .revision = "E2" } +}; + +static const struct regmap_config mt7621_pci_phy_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x700, +}; + +static int mt7621_pci_phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct soc_device_attribute *attr; + struct phy_provider *provider; + struct mt7621_pci_phy *phy; + + phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); + if (!phy) + return -ENOMEM; + + attr = soc_device_match(mt7621_pci_quirks_match); + if (attr) + phy->bypass_pipe_rst = true; + + phy->dev = dev; + platform_set_drvdata(pdev, phy); + + phy->port_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(phy->port_base)) { + dev_err(dev, "failed to remap phy regs\n"); + return PTR_ERR(phy->port_base); + } + + phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base, + &mt7621_pci_phy_regmap_config); + if (IS_ERR(phy->regmap)) + return PTR_ERR(phy->regmap); + + phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + return PTR_ERR(phy); + } + + phy_set_drvdata(phy->phy, phy); + + provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate); + + return PTR_ERR_OR_ZERO(provider); +} + +static const struct of_device_id mt7621_pci_phy_ids[] = { + { .compatible = "mediatek,mt7621-pci-phy" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt7621_pci_ids); + +static struct platform_driver mt7621_pci_phy_driver = { + .probe = mt7621_pci_phy_probe, + .driver = { + .name = "mt7621-pci-phy", + .of_match_table = of_match_ptr(mt7621_pci_phy_ids), + }, +}; + +builtin_platform_driver(mt7621_pci_phy_driver); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Sat Nov 21 15:50:36 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 16:50:36 +0100 Subject: [PATCH v6 3/4] MAINTAINERS: add MT7621 PHY PCI maintainer In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> Message-ID: <20201121155037.21354-4-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 pci phy driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f01ce8f451c8..c07967b9a654 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11108,6 +11108,12 @@ S: Maintained F: Documentation/devicetree/bindings/i2c/i2c-mt7621.txt F: drivers/i2c/busses/i2c-mt7621.c +MEDIATEK MT7621 PHY PCI DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/phy/mediatek,mt7621-pci-phy.yaml +F: drivers/phy/ralink/phy-mt7621-pci.c + MEDIATEK NAND CONTROLLER DRIVER L: linux-mtd at lists.infradead.org S: Orphan -- 2.25.1 From sergio.paracuellos at gmail.com Sat Nov 21 15:50:37 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 16:50:37 +0100 Subject: [PATCH v6 4/4] staging: mt7621-pci-phy: remove driver from staging In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> Message-ID: <20201121155037.21354-5-sergio.paracuellos@gmail.com> Remove this driver from staging because it has been moved into its properly place in the kernel. Signed-off-by: Sergio Paracuellos Acked-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/mt7621-pci-phy/Kconfig | 8 - drivers/staging/mt7621-pci-phy/Makefile | 2 - drivers/staging/mt7621-pci-phy/TODO | 4 - .../mediatek,mt7621-pci-phy.yaml | 36 -- .../staging/mt7621-pci-phy/pci-mt7621-phy.c | 373 ------------------ 7 files changed, 426 deletions(-) delete mode 100644 drivers/staging/mt7621-pci-phy/Kconfig delete mode 100644 drivers/staging/mt7621-pci-phy/Makefile delete mode 100644 drivers/staging/mt7621-pci-phy/TODO delete mode 100644 drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml delete mode 100644 drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 2d0310448eba..8a03ba56def5 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -94,8 +94,6 @@ source "drivers/staging/pi433/Kconfig" source "drivers/staging/mt7621-pci/Kconfig" -source "drivers/staging/mt7621-pci-phy/Kconfig" - source "drivers/staging/mt7621-pinctrl/Kconfig" source "drivers/staging/mt7621-dma/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 757a892ab5b9..39319161301c 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -37,7 +37,6 @@ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ obj-$(CONFIG_PI433) += pi433/ obj-$(CONFIG_PCI_MT7621) += mt7621-pci/ -obj-$(CONFIG_PCI_MT7621_PHY) += mt7621-pci-phy/ obj-$(CONFIG_PINCTRL_RT2880) += mt7621-pinctrl/ obj-$(CONFIG_SOC_MT7621) += mt7621-dma/ obj-$(CONFIG_DMA_RALINK) += ralink-gdma/ diff --git a/drivers/staging/mt7621-pci-phy/Kconfig b/drivers/staging/mt7621-pci-phy/Kconfig deleted file mode 100644 index 263e0a91c424..000000000000 --- a/drivers/staging/mt7621-pci-phy/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config PCI_MT7621_PHY - tristate "MediaTek MT7621 PCI PHY Driver" - depends on RALINK && OF - select GENERIC_PHY - help - Say 'Y' here to add support for MediaTek MT7621 PCI PHY driver, - diff --git a/drivers/staging/mt7621-pci-phy/Makefile b/drivers/staging/mt7621-pci-phy/Makefile deleted file mode 100644 index b4d99b9119e0..000000000000 --- a/drivers/staging/mt7621-pci-phy/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_PCI_MT7621_PHY) += pci-mt7621-phy.o diff --git a/drivers/staging/mt7621-pci-phy/TODO b/drivers/staging/mt7621-pci-phy/TODO deleted file mode 100644 index a255e8f753eb..000000000000 --- a/drivers/staging/mt7621-pci-phy/TODO +++ /dev/null @@ -1,4 +0,0 @@ - -- general code review and cleanup - -Cc: NeilBrown and Sergio Paracuellos diff --git a/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml b/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml deleted file mode 100644 index cf32bbc45b5d..000000000000 --- a/drivers/staging/mt7621-pci-phy/mediatek,mt7621-pci-phy.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -%YAML 1.2 ---- -$id: "http://devicetree.org/schemas/phy/mediatek,mt7621-pci-phy.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" - -title: Mediatek Mt7621 PCIe PHY Device Tree Bindings - -maintainers: - - Sergio Paracuellos - -properties: - compatible: - const: mediatek,mt7621-pci-phy - - reg: - maxItems: 1 - - "#phy-cells": - const: 1 - description: selects if the phy is dual-ported - -required: - - compatible - - reg - - "#phy-cells" - -additionalProperties: false - -examples: - - | - pcie0_phy: pcie-phy at 1e149000 { - compatible = "mediatek,mt7621-pci-phy"; - reg = <0x1e149000 0x0700>; - #phy-cells = <1>; - }; diff --git a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c b/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c deleted file mode 100644 index 57743fd22be4..000000000000 --- a/drivers/staging/mt7621-pci-phy/pci-mt7621-phy.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mediatek MT7621 PCI PHY Driver - * Author: Sergio Paracuellos - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define RG_PE1_PIPE_REG 0x02c -#define RG_PE1_PIPE_RST BIT(12) -#define RG_PE1_PIPE_CMD_FRC BIT(4) - -#define RG_P0_TO_P1_WIDTH 0x100 -#define RG_PE1_H_LCDDS_REG 0x49c -#define RG_PE1_H_LCDDS_PCW GENMASK(30, 0) -#define RG_PE1_H_LCDDS_PCW_VAL(x) ((0x7fffffff & (x)) << 0) - -#define RG_PE1_FRC_H_XTAL_REG 0x400 -#define RG_PE1_FRC_H_XTAL_TYPE BIT(8) -#define RG_PE1_H_XTAL_TYPE GENMASK(10, 9) -#define RG_PE1_H_XTAL_TYPE_VAL(x) ((0x3 & (x)) << 9) - -#define RG_PE1_FRC_PHY_REG 0x000 -#define RG_PE1_FRC_PHY_EN BIT(4) -#define RG_PE1_PHY_EN BIT(5) - -#define RG_PE1_H_PLL_REG 0x490 -#define RG_PE1_H_PLL_BC GENMASK(23, 22) -#define RG_PE1_H_PLL_BC_VAL(x) ((0x3 & (x)) << 22) -#define RG_PE1_H_PLL_BP GENMASK(21, 18) -#define RG_PE1_H_PLL_BP_VAL(x) ((0xf & (x)) << 18) -#define RG_PE1_H_PLL_IR GENMASK(15, 12) -#define RG_PE1_H_PLL_IR_VAL(x) ((0xf & (x)) << 12) -#define RG_PE1_H_PLL_IC GENMASK(11, 8) -#define RG_PE1_H_PLL_IC_VAL(x) ((0xf & (x)) << 8) -#define RG_PE1_H_PLL_PREDIV GENMASK(7, 6) -#define RG_PE1_H_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) -#define RG_PE1_PLL_DIVEN GENMASK(3, 1) -#define RG_PE1_PLL_DIVEN_VAL(x) ((0x7 & (x)) << 1) - -#define RG_PE1_H_PLL_FBKSEL_REG 0x4bc -#define RG_PE1_H_PLL_FBKSEL GENMASK(5, 4) -#define RG_PE1_H_PLL_FBKSEL_VAL(x) ((0x3 & (x)) << 4) - -#define RG_PE1_H_LCDDS_SSC_PRD_REG 0x4a4 -#define RG_PE1_H_LCDDS_SSC_PRD GENMASK(15, 0) -#define RG_PE1_H_LCDDS_SSC_PRD_VAL(x) ((0xffff & (x)) << 0) - -#define RG_PE1_H_LCDDS_SSC_DELTA_REG 0x4a8 -#define RG_PE1_H_LCDDS_SSC_DELTA GENMASK(11, 0) -#define RG_PE1_H_LCDDS_SSC_DELTA_VAL(x) ((0xfff & (x)) << 0) -#define RG_PE1_H_LCDDS_SSC_DELTA1 GENMASK(27, 16) -#define RG_PE1_H_LCDDS_SSC_DELTA1_VAL(x) ((0xff & (x)) << 16) - -#define RG_PE1_LCDDS_CLK_PH_INV_REG 0x4a0 -#define RG_PE1_LCDDS_CLK_PH_INV BIT(5) - -#define RG_PE1_H_PLL_BR_REG 0x4ac -#define RG_PE1_H_PLL_BR GENMASK(18, 16) -#define RG_PE1_H_PLL_BR_VAL(x) ((0x7 & (x)) << 16) - -#define RG_PE1_MSTCKDIV_REG 0x414 -#define RG_PE1_MSTCKDIV GENMASK(7, 6) -#define RG_PE1_MSTCKDIV_VAL(x) ((0x3 & (x)) << 6) - -#define RG_PE1_FRC_MSTCKDIV BIT(5) - -#define XTAL_MODE_SEL_SHIFT 6 -#define XTAL_MODE_SEL_MASK 0x7 - -#define MAX_PHYS 2 - -/** - * struct mt7621_pci_phy - Mt7621 Pcie PHY core - * @dev: pointer to device - * @regmap: kernel regmap pointer - * @phy: pointer to the kernel PHY device - * @port_base: base register - * @has_dual_port: if the phy has dual ports. - * @bypass_pipe_rst: mark if 'mt7621_bypass_pipe_rst' - * needs to be executed. Depends on chip revision. - */ -struct mt7621_pci_phy { - struct device *dev; - struct regmap *regmap; - struct phy *phy; - void __iomem *port_base; - bool has_dual_port; - bool bypass_pipe_rst; -}; - -static inline u32 phy_read(struct mt7621_pci_phy *phy, u32 reg) -{ - u32 val; - - regmap_read(phy->regmap, reg, &val); - - return val; -} - -static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) -{ - regmap_write(phy->regmap, reg, val); -} - -static inline void mt7621_phy_rmw(struct mt7621_pci_phy *phy, - u32 reg, u32 clr, u32 set) -{ - u32 val = phy_read(phy, reg); - - val &= ~clr; - val |= set; - phy_write(phy, val, reg); -} - -static void mt7621_bypass_pipe_rst(struct mt7621_pci_phy *phy) -{ - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_RST); - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG, 0, RG_PE1_PIPE_CMD_FRC); - - if (phy->has_dual_port) { - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, - 0, RG_PE1_PIPE_RST); - mt7621_phy_rmw(phy, RG_PE1_PIPE_REG + RG_P0_TO_P1_WIDTH, - 0, RG_PE1_PIPE_CMD_FRC); - } -} - -static void mt7621_set_phy_for_ssc(struct mt7621_pci_phy *phy) -{ - struct device *dev = phy->dev; - u32 xtal_mode; - - xtal_mode = (rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0) - >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; - - /* Set PCIe Port PHY to disable SSC */ - /* Debug Xtal Type */ - mt7621_phy_rmw(phy, RG_PE1_FRC_H_XTAL_REG, - RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE, - RG_PE1_FRC_H_XTAL_TYPE | RG_PE1_H_XTAL_TYPE_VAL(0x00)); - - /* disable port */ - mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - - if (phy->has_dual_port) { - mt7621_phy_rmw(phy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - } - - if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ - /* Set Pre-divider ratio (for host mode) */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x01)); - dev_info(dev, "Xtal is 40MHz\n"); - } else if (xtal_mode >= 6) { /* 25MHz Xal */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x00)); - /* Select feedback clock */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_FBKSEL_REG, - RG_PE1_H_PLL_FBKSEL, - RG_PE1_H_PLL_FBKSEL_VAL(0x01)); - /* DDS NCPO PCW (for host mode) */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, - RG_PE1_H_LCDDS_SSC_PRD, - RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18000000)); - /* DDS SSC dither period control */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_PRD_REG, - RG_PE1_H_LCDDS_SSC_PRD, - RG_PE1_H_LCDDS_SSC_PRD_VAL(0x18d)); - /* DDS SSC dither amplitude control */ - mt7621_phy_rmw(phy, RG_PE1_H_LCDDS_SSC_DELTA_REG, - RG_PE1_H_LCDDS_SSC_DELTA | - RG_PE1_H_LCDDS_SSC_DELTA1, - RG_PE1_H_LCDDS_SSC_DELTA_VAL(0x4a) | - RG_PE1_H_LCDDS_SSC_DELTA1_VAL(0x4a)); - dev_info(dev, "Xtal is 25MHz\n"); - } else { /* 20MHz Xtal */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_PREDIV, - RG_PE1_H_PLL_PREDIV_VAL(0x00)); - - dev_info(dev, "Xtal is 20MHz\n"); - } - - /* DDS clock inversion */ - mt7621_phy_rmw(phy, RG_PE1_LCDDS_CLK_PH_INV_REG, - RG_PE1_LCDDS_CLK_PH_INV, RG_PE1_LCDDS_CLK_PH_INV); - - /* Set PLL bits */ - mt7621_phy_rmw(phy, RG_PE1_H_PLL_REG, - RG_PE1_H_PLL_BC | RG_PE1_H_PLL_BP | RG_PE1_H_PLL_IR | - RG_PE1_H_PLL_IC | RG_PE1_PLL_DIVEN, - RG_PE1_H_PLL_BC_VAL(0x02) | RG_PE1_H_PLL_BP_VAL(0x06) | - RG_PE1_H_PLL_IR_VAL(0x02) | RG_PE1_H_PLL_IC_VAL(0x01) | - RG_PE1_PLL_DIVEN_VAL(0x02)); - - mt7621_phy_rmw(phy, RG_PE1_H_PLL_BR_REG, - RG_PE1_H_PLL_BR, RG_PE1_H_PLL_BR_VAL(0x00)); - - if (xtal_mode <= 5 && xtal_mode >= 3) { /* 40MHz Xtal */ - /* set force mode enable of da_pe1_mstckdiv */ - mt7621_phy_rmw(phy, RG_PE1_MSTCKDIV_REG, - RG_PE1_MSTCKDIV | RG_PE1_FRC_MSTCKDIV, - RG_PE1_MSTCKDIV_VAL(0x01) | RG_PE1_FRC_MSTCKDIV); - } -} - -static int mt7621_pci_phy_init(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - if (mphy->bypass_pipe_rst) - mt7621_bypass_pipe_rst(mphy); - - mt7621_set_phy_for_ssc(mphy); - - return 0; -} - -static int mt7621_pci_phy_power_on(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - /* Enable PHY and disable force mode */ - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, - RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); - - if (mphy->has_dual_port) { - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_FRC_PHY_EN, RG_PE1_PHY_EN); - } - - return 0; -} - -static int mt7621_pci_phy_power_off(struct phy *phy) -{ - struct mt7621_pci_phy *mphy = phy_get_drvdata(phy); - - /* Disable PHY */ - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - - if (mphy->has_dual_port) { - mt7621_phy_rmw(mphy, RG_PE1_FRC_PHY_REG + RG_P0_TO_P1_WIDTH, - RG_PE1_PHY_EN, RG_PE1_FRC_PHY_EN); - } - - return 0; -} - -static int mt7621_pci_phy_exit(struct phy *phy) -{ - return 0; -} - -static const struct phy_ops mt7621_pci_phy_ops = { - .init = mt7621_pci_phy_init, - .exit = mt7621_pci_phy_exit, - .power_on = mt7621_pci_phy_power_on, - .power_off = mt7621_pci_phy_power_off, - .owner = THIS_MODULE, -}; - -static struct phy *mt7621_pcie_phy_of_xlate(struct device *dev, - struct of_phandle_args *args) -{ - struct mt7621_pci_phy *mt7621_phy = dev_get_drvdata(dev); - - if (WARN_ON(args->args[0] >= MAX_PHYS)) - return ERR_PTR(-ENODEV); - - mt7621_phy->has_dual_port = args->args[0]; - - dev_info(dev, "PHY for 0x%08x (dual port = %d)\n", - (unsigned int)mt7621_phy->port_base, mt7621_phy->has_dual_port); - - return mt7621_phy->phy; -} - -static const struct soc_device_attribute mt7621_pci_quirks_match[] = { - { .soc_id = "mt7621", .revision = "E2" } -}; - -static const struct regmap_config mt7621_pci_phy_regmap_config = { - .reg_bits = 32, - .val_bits = 32, - .reg_stride = 4, - .max_register = 0x700, -}; - -static int mt7621_pci_phy_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - const struct soc_device_attribute *attr; - struct phy_provider *provider; - struct mt7621_pci_phy *phy; - struct resource *res; - - phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); - if (!phy) - return -ENOMEM; - - attr = soc_device_match(mt7621_pci_quirks_match); - if (attr) - phy->bypass_pipe_rst = true; - - phy->dev = dev; - platform_set_drvdata(pdev, phy); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "failed to get address resource\n"); - return -ENXIO; - } - - phy->port_base = devm_ioremap_resource(dev, res); - if (IS_ERR(phy->port_base)) { - dev_err(dev, "failed to remap phy regs\n"); - return PTR_ERR(phy->port_base); - } - - phy->regmap = devm_regmap_init_mmio(phy->dev, phy->port_base, - &mt7621_pci_phy_regmap_config); - if (IS_ERR(phy->regmap)) - return PTR_ERR(phy->regmap); - - phy->phy = devm_phy_create(dev, dev->of_node, &mt7621_pci_phy_ops); - if (IS_ERR(phy)) { - dev_err(dev, "failed to create phy\n"); - return PTR_ERR(phy); - } - - phy_set_drvdata(phy->phy, phy); - - provider = devm_of_phy_provider_register(dev, mt7621_pcie_phy_of_xlate); - - return PTR_ERR_OR_ZERO(provider); -} - -static const struct of_device_id mt7621_pci_phy_ids[] = { - { .compatible = "mediatek,mt7621-pci-phy" }, - {}, -}; -MODULE_DEVICE_TABLE(of, mt7621_pci_ids); - -static struct platform_driver mt7621_pci_phy_driver = { - .probe = mt7621_pci_phy_probe, - .driver = { - .name = "mt7621-pci-phy", - .of_match_table = of_match_ptr(mt7621_pci_phy_ids), - }, -}; - -builtin_platform_driver(mt7621_pci_phy_driver); - -MODULE_AUTHOR("Sergio Paracuellos "); -MODULE_DESCRIPTION("MediaTek MT7621 PCIe PHY driver"); -MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Sat Nov 21 16:22:58 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sat, 21 Nov 2020 17:22:58 +0100 Subject: [PATCH v3 2/5] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: References: <20201113154632.24973-1-sergio.paracuellos@gmail.com> <20201113154632.24973-3-sergio.paracuellos@gmail.com> <20201121133432.GA2130098@robh.at.kernel.org> Message-ID: On Sat, Nov 21, 2020 at 3:50 PM Sergio Paracuellos wrote: > > Hi Rob, > > Thanks for the review. > > On Sat, Nov 21, 2020 at 2:34 PM Rob Herring wrote: > > > > On Fri, Nov 13, 2020 at 04:46:29PM +0100, Sergio Paracuellos wrote: > > > Adds device tree binding documentation for clocks in the > > > MT7621 SOC. > > > > > > Signed-off-by: Sergio Paracuellos > > > --- > > > .../bindings/clock/mediatek,mt7621-clk.yaml | 61 +++++++++++++++++++ > > > 1 file changed, 61 insertions(+) > > > create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > > > > > diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > > new file mode 100644 > > > index 000000000000..363bd9880e29 > > > --- /dev/null > > > +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml > > > @@ -0,0 +1,61 @@ > > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) > > > +%YAML 1.2 > > > +--- > > > +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# > > > +$schema: http://devicetree.org/meta-schemas/core.yaml# > > > + > > > +title: MT7621 Clock Device Tree Bindings > > > + > > > +maintainers: > > > + - Sergio Paracuellos > > > + > > > +description: | > > > + The MT7621 has a PLL controller from where the cpu clock is provided > > > + as well as derived clocks for the bus and the peripherals. It also > > > + can gate SoC device clocks. > > > + > > > + Each clock is assigned an identifier and client nodes use this identifier > > > + to specify the clock which they consume. > > > + > > > + All these identifiers could be found in: > > > + [1]: . > > > + > > > +properties: > > > + compatible: > > > + const: mediatek,mt7621-clk > > > + > > > + ralink,sysctl: > > > + $ref: /schemas/types.yaml#/definitions/phandle > > > + description: > > > + phandle to the syscon which is in the same address area with syscon > > > + device. > > > + > > > + "#clock-cells": > > > + description: > > > + The first cell indicates the clock gate number, see [1] for available > > > + clocks. > > > + const: 1 > > > + > > > + clock-output-names: > > > + maxItems: 8 > > > + > > > +required: > > > + - compatible > > > + - ralink,sysctl > > > + - '#clock-cells' > > > + - clock-output-names > > > + > > > +additionalProperties: false > > > + > > > +examples: > > > + - | > > > + #include > > > + > > > + pll { > > > + compatible = "mediatek,mt7621-clk"; > > > + ralink,sysctl = <&sysc>; > > > > If this is the only control interface, then make this a child of 'sysc'. > > And use 'reg' if there's a dedicated range of registers. > > This is the only one now in the device tree which is still in staging > but there are several places where this sys control registers are > accessed from. In the case of the clocks we need: > > #define SYSC_REG_SYSTEM_CONFIG0 0x10 > #define SYSC_REG_SYSTEM_CONFIG1 0x14 > #define SYSC_REG_CLKCFG0 0x2c > #define SYSC_REG_CLKCFG1 0x30 > #define SYSC_REG_CUR_CLK_STS 0x44 > > where there is not a range as it is but several different registers > from where we need to read or write things. I wrote the driver using > syscon and regmap because I thought in that way it might be more > maintainable but this architecture also has operations to read and > write registers from sysc and not using regmap at all. This operations > are defined in arch/mips/include/asm/mach-ralink/ralink_regs.h. But > because this sysc is currently mapped I cannot request its registers > using reg in the device tree. If you prefer me to avoid the use of > this syscon and regmap and use operations defined in ralink_regs.h, > this will become in a node without "regs" or "ralink,sysctl" > property: > > pll { > compatible = "mediatek,mt7621-clk"; > #clock-cells = <1>; > clock-output-names = "xtal", "cpu", "bus", > "50m", "125m", "150m", > "250m", "270m"; > }; > > What should I do then? Ok, I think I understand now what you are saying. You meant just move this as a child if 'sysc' and avoid the phandle: sysc: sysc at 0 { compatible = "mtk,mt7621-sysc", "syscon"; reg = <0x0 0x100>; pll: pll { compatible = "mediatek,mt7621-clk"; #clock-cells = <1>; clock-output-names = "xtal", "cpu", "bus", "50m", "125m", "150m", "250m", "270m"; }; }; And because there is not a range of registers 'reg' property is not needed, right? And in the driver side make use of 'syscon_node_to_regmap(node->parent)' instead of 'syscon_regmap_lookup_by_phandle(node, "ralink,sysctl")'. Ok, thanks for the clarification. Will change when v4 is sent. Best regards, Sergio Paracuellos > > Best regards, > Sergio Paracuellos > > > > > > + #clock-cells = <1>; > > > + clock-output-names = "xtal", "cpu", "bus", > > > + "50m", "125m", "150m", > > > + "250m", "270m"; > > > + }; > > > -- > > > 2.25.1 > > > From tkjos at google.com Sat Nov 21 17:11:42 2020 From: tkjos at google.com (Todd Kjos) Date: Sat, 21 Nov 2020 09:11:42 -0800 Subject: [PATCH] binder: add flag to clear buffer on txn complete In-Reply-To: References: <20201120233743.3617529-1-tkjos@google.com> Message-ID: On Fri, Nov 20, 2020 at 11:14 PM Greg KH wrote: > > On Fri, Nov 20, 2020 at 03:37:43PM -0800, Todd Kjos wrote: > > Add a per-transaction flag to indicate that the buffer > > must be cleared when the transaction is complete to > > prevent copies of sensitive data from being preserved > > in memory. > > > > Signed-off-by: Todd Kjos > > --- > > DOes this need to be backported to stable kernels as well? It doesn't technically qualify for stable since it is a new feature -- not a bug fix. We will want it for Android S launch devices (5.4+), so it would be handy to have it in 5.4.y and later. > > thanks, > > greg k-h > > -- > To unsubscribe from this group and stop receiving emails from it, send an email to kernel-team+unsubscribe at android.com. > From financialcapability6 at gmail.com Sat Nov 21 18:59:23 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Sat, 21 Nov 2020 10:59:23 -0800 Subject: Corporate and Personal Loan ,= Message-ID: <20201121192220.4CF7B86D58@whitealder.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From financialcapability6 at gmail.com Sat Nov 21 19:19:59 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Sat, 21 Nov 2020 11:19:59 -0800 Subject: Corporate and Personal Loan ,= Message-ID: <20201121192842.8FF9620488@silver.osuosl.org> Hello driverdev-devel at linuxdriverproject.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From financialcapability6 at gmail.com Sat Nov 21 19:20:04 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Sat, 21 Nov 2020 11:20:04 -0800 Subject: Corporate and Personal Loan ,= Message-ID: <20201121194900.5D52487219@hemlock.osuosl.org> Hello devel at linuxdriverproject.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From ezequiel at vanguardiasur.com.ar Sun Nov 22 01:02:15 2020 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Sat, 21 Nov 2020 22:02:15 -0300 Subject: [PATCH v5 2/4] staging: media: Introduce NVIDIA Tegra video decoder driver In-Reply-To: <3d565db80f8dccafd14224924305243b37b75a07.1513038011.git.digetx@gmail.com> References: <3d565db80f8dccafd14224924305243b37b75a07.1513038011.git.digetx@gmail.com> Message-ID: Hi Dmitry, On Mon, 11 Dec 2017 at 21:27, Dmitry Osipenko wrote: > > NVIDIA Tegra20/30/114/124/132 SoC's have video decoder engine that > supports standard set of video formats like H.264 / MPEG-4 / WMV / VC1. > > Signed-off-by: Dmitry Osipenko > --- > MAINTAINERS | 9 + > drivers/staging/media/Kconfig | 2 + > drivers/staging/media/Makefile | 1 + > drivers/staging/media/tegra-vde/Kconfig | 7 + > drivers/staging/media/tegra-vde/Makefile | 1 + > drivers/staging/media/tegra-vde/TODO | 4 + > drivers/staging/media/tegra-vde/tegra-vde.c | 1213 +++++++++++++++++++++++++++ > drivers/staging/media/tegra-vde/uapi.h | 78 ++ > 8 files changed, 1315 insertions(+) > create mode 100644 drivers/staging/media/tegra-vde/Kconfig > create mode 100644 drivers/staging/media/tegra-vde/Makefile > create mode 100644 drivers/staging/media/tegra-vde/TODO > create mode 100644 drivers/staging/media/tegra-vde/tegra-vde.c > create mode 100644 drivers/staging/media/tegra-vde/uapi.h > > diff --git a/MAINTAINERS b/MAINTAINERS > index 7d195739f892..7f7c24949a06 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -8706,6 +8706,15 @@ T: git git://linuxtv.org/media_tree.git > S: Maintained > F: drivers/media/dvb-frontends/stv6111* > > +MEDIA DRIVERS FOR NVIDIA TEGRA - VDE > +M: Dmitry Osipenko > +L: linux-media at vger.kernel.org > +L: linux-tegra at vger.kernel.org > +T: git git://linuxtv.org/media_tree.git > +S: Maintained > +F: Documentation/devicetree/bindings/media/nvidia,tegra-vde.txt > +F: drivers/staging/media/tegra-vde/ > + > MEDIA INPUT INFRASTRUCTURE (V4L/DVB) > M: Mauro Carvalho Chehab > M: Mauro Carvalho Chehab > diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig > index 3a09140700e6..227437f22acf 100644 > --- a/drivers/staging/media/Kconfig > +++ b/drivers/staging/media/Kconfig > @@ -31,4 +31,6 @@ source "drivers/staging/media/imx/Kconfig" > > source "drivers/staging/media/omap4iss/Kconfig" > > +source "drivers/staging/media/tegra-vde/Kconfig" > + > endif > diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile > index f25327163c67..59a47f69884f 100644 > --- a/drivers/staging/media/Makefile > +++ b/drivers/staging/media/Makefile > @@ -5,3 +5,4 @@ obj-$(CONFIG_VIDEO_IMX_MEDIA) += imx/ > obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ > obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ > obj-$(CONFIG_INTEL_ATOMISP) += atomisp/ > +obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ > diff --git a/drivers/staging/media/tegra-vde/Kconfig b/drivers/staging/media/tegra-vde/Kconfig > new file mode 100644 > index 000000000000..ec3ddddebdaa > --- /dev/null > +++ b/drivers/staging/media/tegra-vde/Kconfig > @@ -0,0 +1,7 @@ > +config TEGRA_VDE > + tristate "NVIDIA Tegra Video Decoder Engine driver" > + depends on ARCH_TEGRA || COMPILE_TEST > + select SRAM > + help > + Say Y here to enable support for the NVIDIA Tegra video decoder > + driver. > diff --git a/drivers/staging/media/tegra-vde/Makefile b/drivers/staging/media/tegra-vde/Makefile > new file mode 100644 > index 000000000000..444c1d62daa1 > --- /dev/null > +++ b/drivers/staging/media/tegra-vde/Makefile > @@ -0,0 +1 @@ > +obj-$(CONFIG_TEGRA_VDE) += tegra-vde.o > diff --git a/drivers/staging/media/tegra-vde/TODO b/drivers/staging/media/tegra-vde/TODO > new file mode 100644 > index 000000000000..31aaa3e66d80 > --- /dev/null > +++ b/drivers/staging/media/tegra-vde/TODO > @@ -0,0 +1,4 @@ > +TODO: > + - Implement V4L2 API once it gains support for stateless decoders. > + > +Contact: Dmitry Osipenko The API for H264 stateless decoding is ready. See https://lkml.org/lkml/2020/11/18/795. One minor comment below. > diff --git a/drivers/staging/media/tegra-vde/uapi.h b/drivers/staging/media/tegra-vde/uapi.h > new file mode 100644 > index 000000000000..a50c7bcae057 > --- /dev/null > +++ b/drivers/staging/media/tegra-vde/uapi.h > @@ -0,0 +1,78 @@ > +/* > + * Copyright (C) 2016-2017 Dmitry Osipenko > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * as published by the Free Software Foundation; either version > + * 2 of the License, or (at your option) any later version. > + */ > + > +#ifndef _UAPI_TEGRA_VDE_H_ > +#define _UAPI_TEGRA_VDE_H_ > + > +#include > +#include > + > +#define FLAG_B_FRAME (1 << 0) > +#define FLAG_REFERENCE (1 << 1) > + > +struct tegra_vde_h264_frame { > + __s32 y_fd; > + __s32 cb_fd; > + __s32 cr_fd; > + __s32 aux_fd; > + __u32 y_offset; > + __u32 cb_offset; > + __u32 cr_offset; > + __u32 aux_offset; > + __u32 frame_num; > + __u32 flags; > + > + __u32 reserved; > +} __attribute__((packed)); > + > +struct tegra_vde_h264_decoder_ctx { > + __s32 bitstream_data_fd; > + __u32 bitstream_data_offset; > + > + __u64 dpb_frames_ptr; > + __u8 dpb_frames_nb; > + __u8 dpb_ref_frames_with_earlier_poc_nb; > + > + // SPS > + __u8 baseline_profile; > + __u8 level_idc; > + __u8 log2_max_pic_order_cnt_lsb; > + __u8 log2_max_frame_num; > + __u8 pic_order_cnt_type; > + __u8 direct_8x8_inference_flag; > + __u8 pic_width_in_mbs; > + __u8 pic_height_in_mbs; > + > + // PPS > + __u8 pic_init_qp; > + __u8 deblocking_filter_control_present_flag; > + __u8 constrained_intra_pred_flag; > + __u8 chroma_qp_index_offset; > + __u8 pic_order_present_flag; > + This seems to be bottom_field_pic_order_in_frame_present_flag, as there is no "pic_order_present_flag" syntax element. Thanks, Ezequiel From digetx at gmail.com Sun Nov 22 02:01:09 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Sun, 22 Nov 2020 05:01:09 +0300 Subject: [PATCH v5 2/4] staging: media: Introduce NVIDIA Tegra video decoder driver In-Reply-To: References: <3d565db80f8dccafd14224924305243b37b75a07.1513038011.git.digetx@gmail.com> Message-ID: <5665b221-04d7-6be9-2377-8006b9563d4b@gmail.com> 22.11.2020 04:02, Ezequiel Garcia ?????: > Hi Dmitry, > ... >> +++ b/drivers/staging/media/tegra-vde/TODO >> @@ -0,0 +1,4 @@ >> +TODO: >> + - Implement V4L2 API once it gains support for stateless decoders. >> + >> +Contact: Dmitry Osipenko > > The API for H264 stateless decoding is ready. > See https://lkml.org/lkml/2020/11/18/795. Hello Ezequiel, Thank you for the notification! My last attempt at implementing V4L API support was about a year ago and it stopped once I realized that there is no userspace which uses that API. FFMPEG and chromium browser had some kind of V4L support, but it all was oriented at downstream driver stacks, and thus, not usable. Do you know what is the current status? > One minor comment below. > ... >> + // PPS >> + __u8 pic_init_qp; >> + __u8 deblocking_filter_control_present_flag; >> + __u8 constrained_intra_pred_flag; >> + __u8 chroma_qp_index_offset; >> + __u8 pic_order_present_flag; >> + > > This seems to be bottom_field_pic_order_in_frame_present_flag, > as there is no "pic_order_present_flag" syntax element. Correct, looks like I borrowed that name from the libvdpau API. https://vdpau.pages.freedesktop.org/libvdpau/struct_vdp_picture_info_h264.html#a405f7ef26ea76bb2c446e151062fc001 From nami at 4sasa.xyz Sun Nov 22 03:40:18 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Sun, 22 Nov 2020 11:40:18 +0800 Subject: GREETINGS DEAR BELOVED: Message-ID: <20201122034024.F2D3F20450@silver.osuosl.org> Dear Beloved , Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of 10,000,000.00 Euro (Ten Million EUR) to you. Upon your acknowledgement of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity to help the less privileged. Sincere regards, Ms. Melvida Bullock Email:?melvidabullock at gmail.com From nami at 4sasa.xyz Sun Nov 22 04:15:45 2020 From: nami at 4sasa.xyz (Ms. Melvida Bullock) Date: Sun, 22 Nov 2020 12:15:45 +0800 Subject: GREETINGS DEAR BELOVED: Message-ID: <20201122041558.72069203A5@silver.osuosl.org> Dear Beloved , Life is gradually passing away from me as a result of my present medical condition and my personal doctor confided in me yesterday that I have only but few more weeks to live. In view of this setback, I want to donate my estate for humanitarian assistance, since this has always been the plan of my late husband and besides I have no child. In an effort to compliment the good work of our creator for humanity and the wish of my late Husband I donate the sum of 10,000,000.00 Euro (Ten Million EUR) to you. Upon your acknowledgement of this mail and informing me of your nationality and current place of resident, my Bank will facilitate due processes for transfer of this legacy to you. May God bless you as you use this money judiciously for the work of charity to help the less privileged. Sincere regards, Ms. Melvida Bullock Email:?melvidabullock at gmail.com From financialcapability6 at gmail.com Sun Nov 22 03:59:35 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Sat, 21 Nov 2020 19:59:35 -0800 Subject: Corporate and Personal Loan ,= Message-ID: <20201122042817.D4AF920467@silver.osuosl.org> Hello driverdev-devel at linuxdriverproject.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From sergio.paracuellos at gmail.com Sun Nov 22 09:55:50 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:50 +0100 Subject: [PATCH v4 0/6] MIPS: ralink: add CPU clock detection and clock driver for MT7621 Message-ID: <20201122095556.21597-1-sergio.paracuellos@gmail.com> This patchset ports CPU clock detection for MT7621 from OpenWrt and adds a complete clock plan for the mt7621 SOC. The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS (AHB?). * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. No documentation about a probably existent set of dividers for each ip core is included in the datasheets. So we cannot make anything better, AFAICT. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: - "hsdma": "150m" - "fe": "250m" - "sp_divtx": "270m" - "timer": "50m" - "pcm": "270m" - "pio": "50m" - "gdma": "bus" - "nand": "125m" - "i2c": "50m" - "i2s": "270m" - "spi": "bus" - "uart1": "50m" - "uart2": "50m" - "uart3": "50m" - "eth": "50m" - "pcie0": "125m" - "pcie1": "125m" - "pcie2": "125m" - "crypto": "250m" - "shxc": "50m" There was a previous attempt of doing this here[0] but the author (Chuanhong Guo) did not wanted to make assumptions of a clock plan for the platform that time. It seems that now he has a better idea of how the clocks are dispossed for this SoC so he share code[1] where some frequencies and clock parents for the gates are coded from a real mediatek private clock plan. I do really want this to be upstreamed so according to the comments in previous attempt[0] from Oleksij Rempel and the frequencies in code[1] I have tried to do this by myself. All of this patches have been tested in a GNUBee PC1 resulting in a working platform. Changes in v4: - Add Acked-by from Rob Herring for binding headers (PATCH 1/6). - Convert bindings to not use syscon phandle and declare clock as a child of the syscon node. Update device tree and binding doc accordly. - Make use of 'syscon_node_to_regmap' in driver code instead of get this using the phandle function. - Properly unregister clocks for the error path of the function 'mt7621_clk_init'. - Include ARRAY_SIZE of fixed clocks in the 'count' to kzalloc of 'clk_data'. - Add new patch changing invalid vendor 'mtk' in favour of 'mediatek' which is the one listed in 'vendor-prefixes.yaml'. Update mt7621 code accordly. I have added this patch inside this series because clk binding is referring syscon node and the string for that node was with not listed vendor. Hence update and have all of this correct in the same series. Changes in v3: - Fix compilation warnings reported by kernel test robot because of ignoring return values of 'of_clk_hw_register' in functions 'mt7621_register_top_clocks' and 'mt7621_gate_ops_init'. - Fix dts file and binding documentation 'clock-output-names'. Changes in v2: - Remove the following patches: * dt: bindings: add mt7621-pll device tree binding documentation. * MIPS: ralink: add clock device providing cpu/ahb/apb clock for mt7621. - Move all relevant clock code to 'drivers/clk/ralink/clk-mt7621.c' and unify there previous 'mt7621-pll' and 'mt7621-clk' into a unique driver and binding 'mt7621-clk'. - Driver is not a platform driver anymore and now make use of 'CLK_OF_DECLARE' because we need clocks available in 'plat_time_init' before setting up the timer for the GIC. - Use new fixed clocks as parents for different gates and deriving from 'xtal' using frequencies in[1]. - Adapt dts file and bindings header and documentation for new changes. - Change MAINTAINERS file to only contains clk-mt7621.c code and mediatek,mt7621-clk.yaml file. [0]: https://www.lkml.org/lkml/2019/7/23/1044 [1]: https://github.com/981213/linux/commit/2eca1f045e4c3db18c941135464c0d7422ad8133 Sergio Paracuellos (6): dt-bindings: clock: add dt binding header for mt7621 clocks dt: bindings: add mt7621-clk device tree binding documentation clk: ralink: add clock driver for mt7621 SoC staging: mt7621-dts: make use of new 'mt7621-clk' staging: mt7621-dts: use valid vendor 'mediatek' instead of invalid 'mtk' MAINTAINERS: add MT7621 CLOCK maintainer .../bindings/clock/mediatek,mt7621-clk.yaml | 67 +++ MAINTAINERS | 6 + arch/mips/ralink/mt7621.c | 6 +- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 + drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 434 ++++++++++++++++++ drivers/staging/mt7621-dts/gbpc1.dts | 11 - drivers/staging/mt7621-dts/mt7621.dtsi | 85 ++-- include/dt-bindings/clock/mt7621-clk.h | 41 ++ 11 files changed, 609 insertions(+), 59 deletions(-) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c create mode 100644 include/dt-bindings/clock/mt7621-clk.h -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:51 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:51 +0100 Subject: [PATCH v4 1/6] dt-bindings: clock: add dt binding header for mt7621 clocks In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-2-sergio.paracuellos@gmail.com> Adds dt binding header for 'mediatek,mt7621-clk' clocks. Acked-by: Rob Herring Signed-off-by: Sergio Paracuellos --- include/dt-bindings/clock/mt7621-clk.h | 41 ++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 include/dt-bindings/clock/mt7621-clk.h diff --git a/include/dt-bindings/clock/mt7621-clk.h b/include/dt-bindings/clock/mt7621-clk.h new file mode 100644 index 000000000000..1422badcf9de --- /dev/null +++ b/include/dt-bindings/clock/mt7621-clk.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Author: Sergio Paracuellos + */ + +#ifndef _DT_BINDINGS_CLK_MT7621_H +#define _DT_BINDINGS_CLK_MT7621_H + +#define MT7621_CLK_XTAL 0 +#define MT7621_CLK_CPU 1 +#define MT7621_CLK_BUS 2 +#define MT7621_CLK_50M 3 +#define MT7621_CLK_125M 4 +#define MT7621_CLK_150M 5 +#define MT7621_CLK_250M 6 +#define MT7621_CLK_270M 7 + +#define MT7621_CLK_HSDMA 8 +#define MT7621_CLK_FE 9 +#define MT7621_CLK_SP_DIVTX 10 +#define MT7621_CLK_TIMER 11 +#define MT7621_CLK_PCM 12 +#define MT7621_CLK_PIO 13 +#define MT7621_CLK_GDMA 14 +#define MT7621_CLK_NAND 15 +#define MT7621_CLK_I2C 16 +#define MT7621_CLK_I2S 17 +#define MT7621_CLK_SPI 18 +#define MT7621_CLK_UART1 19 +#define MT7621_CLK_UART2 20 +#define MT7621_CLK_UART3 21 +#define MT7621_CLK_ETH 22 +#define MT7621_CLK_PCIE0 23 +#define MT7621_CLK_PCIE1 24 +#define MT7621_CLK_PCIE2 25 +#define MT7621_CLK_CRYPTO 26 +#define MT7621_CLK_SHXC 27 + +#define MT7621_CLK_MAX 28 + +#endif /* _DT_BINDINGS_CLK_MT7621_H */ -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:52 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:52 +0100 Subject: [PATCH v4 2/6] dt: bindings: add mt7621-clk device tree binding documentation In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-3-sergio.paracuellos@gmail.com> Adds device tree binding documentation for clocks in the MT7621 SOC. Signed-off-by: Sergio Paracuellos --- .../bindings/clock/mediatek,mt7621-clk.yaml | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml diff --git a/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml new file mode 100644 index 000000000000..6aca4c1a4a46 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml @@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/mediatek,mt7621-clk.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: MT7621 Clock Device Tree Bindings + +maintainers: + - Sergio Paracuellos + +description: | + The MT7621 has a PLL controller from where the cpu clock is provided + as well as derived clocks for the bus and the peripherals. It also + can gate SoC device clocks. + + Each clock is assigned an identifier and client nodes use this identifier + to specify the clock which they consume. + + All these identifiers could be found in: + [1]: . + + The mt7621 clock node should be the child of a syscon node with the + required property: + + - compatible: Should be one of the following: + "mediatek,mt7621-sysc", "syscon" + + Refer to the bindings described in + Documentation/devicetree/bindings/mfd/syscon.yaml + +properties: + compatible: + const: mediatek,mt7621-clk + + "#clock-cells": + description: + The first cell indicates the clock gate number, see [1] for available + clocks. + const: 1 + + clock-output-names: + maxItems: 8 + +required: + - compatible + - '#clock-cells' + - clock-output-names + +additionalProperties: false + +examples: + - | + #include + + sysc: sysc at 0 { + compatible = "mediatek,mt7621-sysc", "syscon"; + reg = <0x0 0x100>; + + pll { + compatible = "mediatek,mt7621-clk"; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "250m", "270m"; + }; + }; -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:53 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:53 +0100 Subject: [PATCH v4 3/6] clk: ralink: add clock driver for mt7621 SoC In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-4-sergio.paracuellos@gmail.com> The documentation for this SOC only talks about two registers regarding to the clocks: * SYSC_REG_CPLL_CLKCFG0 - provides some information about boostrapped refclock. PLL and dividers used for CPU and some sort of BUS. * SYSC_REG_CPLL_CLKCFG1 - a banch of gates to enable/disable clocks for all or some ip cores. Looking into driver code, and some openWRT patched there are another frequences which are used in some drivers (uart, sd...). According to all of this information the clock plan for this SoC is set as follows: - Main top clock "xtal" from where all the rest of the world is derived. - CPU clock "cpu" derived from "xtal" frequencies and a bunch of register reads and predividers. - BUS clock "bus" derived from "cpu" and with (cpu / 4) MHz. - Fixed clocks from "xtal": * "50m": 50 MHz. * "125m": 125 MHz. * "150m": 150 MHz. * "250m": 250 MHz. * "270m": 270 MHz. We also have a buch of gate clocks with their parents: * "hsdma": "150m" * "fe": "250m" * "sp_divtx": "270m" * "timer": "50m" * "pcm": "270m" * "pio": "50m" * "gdma": "bus" * "nand": "125m" * "i2c": "50m" * "i2s": "270m" * "spi": "bus" * "uart1": "50m" * "uart2": "50m" * "uart3": "50m" * "eth": "50m" * "pcie0": "125m" * "pcie1": "125m" * "pcie2": "125m" * "crypto": "250m" * "shxc": "50m" With this information the clk driver will provide clock and gates functionality from a a set of hardcoded clocks allowing to define a nice device tree without fixed clocks. Signed-off-by: Sergio Paracuellos --- drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/ralink/Kconfig | 14 + drivers/clk/ralink/Makefile | 2 + drivers/clk/ralink/clk-mt7621.c | 435 ++++++++++++++++++++++++++++++++ 5 files changed, 453 insertions(+) create mode 100644 drivers/clk/ralink/Kconfig create mode 100644 drivers/clk/ralink/Makefile create mode 100644 drivers/clk/ralink/clk-mt7621.c diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index c715d4681a0b..5f94c4329033 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -372,6 +372,7 @@ source "drivers/clk/mediatek/Kconfig" source "drivers/clk/meson/Kconfig" source "drivers/clk/mvebu/Kconfig" source "drivers/clk/qcom/Kconfig" +source "drivers/clk/ralink/Kconfig" source "drivers/clk/renesas/Kconfig" source "drivers/clk/rockchip/Kconfig" source "drivers/clk/samsung/Kconfig" diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index da8fcf147eb1..6578e167b047 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ +obj-y += ralink/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ diff --git a/drivers/clk/ralink/Kconfig b/drivers/clk/ralink/Kconfig new file mode 100644 index 000000000000..7e8697327e0c --- /dev/null +++ b/drivers/clk/ralink/Kconfig @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# MediaTek Mt7621 Clock Driver +# +menu "Clock driver for mediatek mt7621 SoC" + depends on SOC_MT7621 || COMPILE_TEST + +config CLK_MT7621 + bool "Clock driver for MediaTek MT7621" + depends on SOC_MT7621 || COMPILE_TEST + default SOC_MT7621 + help + This driver supports MediaTek MT7621 basic clocks. +endmenu diff --git a/drivers/clk/ralink/Makefile b/drivers/clk/ralink/Makefile new file mode 100644 index 000000000000..cf6f9216379d --- /dev/null +++ b/drivers/clk/ralink/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_CLK_MT7621) += clk-mt7621.o diff --git a/drivers/clk/ralink/clk-mt7621.c b/drivers/clk/ralink/clk-mt7621.c new file mode 100644 index 000000000000..4e929f13fe7c --- /dev/null +++ b/drivers/clk/ralink/clk-mt7621.c @@ -0,0 +1,435 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Mediatek MT7621 Clock Driver + * Author: Sergio Paracuellos + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Configuration registers */ +#define SYSC_REG_SYSTEM_CONFIG0 0x10 +#define SYSC_REG_SYSTEM_CONFIG1 0x14 +#define SYSC_REG_CLKCFG0 0x2c +#define SYSC_REG_CLKCFG1 0x30 +#define SYSC_REG_CUR_CLK_STS 0x44 + +#define MEMC_REG_CPU_PLL 0x648 +#define XTAL_MODE_SEL_MASK 0x7 +#define XTAL_MODE_SEL_SHIFT 6 + +#define CPU_CLK_SEL_MASK 0x3 +#define CPU_CLK_SEL_SHIFT 30 + +#define CUR_CPU_FDIV_MASK 0x1f +#define CUR_CPU_FDIV_SHIFT 8 +#define CUR_CPU_FFRAC_MASK 0x1f +#define CUR_CPU_FFRAC_SHIFT 0 + +#define CPU_PLL_PREDIV_MASK 0x3 +#define CPU_PLL_PREDIV_SHIFT 12 +#define CPU_PLL_FBDIV_MASK 0x7f +#define CPU_PLL_FBDIV_SHIFT 4 + +#define MHZ(x) ((x) * 1000 * 1000) + +struct mt7621_clk_provider { + struct device_node *node; + struct regmap *syscon_regmap; + struct clk_hw_onecell_data *clk_data; +}; + +struct mt7621_clk { + struct mt7621_clk_provider *clk_prov; + struct clk_hw hw; +}; + +struct mt7621_fixed_clk { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + unsigned long rate; + struct clk_hw *hw; +}; + +struct mt7621_gate { + u8 idx; + const char *name; + const char *parent_name; + struct mt7621_clk_provider *clk_prov; + u32 bit_idx; + struct clk_hw hw; +}; + +#define GATE(_id, _name, _pname, _shift) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .bit_idx = _shift \ + } + +static struct mt7621_gate mt7621_gates[] = { + GATE(MT7621_CLK_HSDMA, "hsdma", "150m", BIT(5)), + GATE(MT7621_CLK_FE, "fe", "250m", BIT(6)), + GATE(MT7621_CLK_SP_DIVTX, "sp_divtx", "270m", BIT(7)), + GATE(MT7621_CLK_TIMER, "timer", "50m", BIT(8)), + GATE(MT7621_CLK_PCM, "pcm", "270m", BIT(11)), + GATE(MT7621_CLK_PIO, "pio", "50m", BIT(13)), + GATE(MT7621_CLK_GDMA, "gdma", "bus", BIT(14)), + GATE(MT7621_CLK_NAND, "nand", "125m", BIT(15)), + GATE(MT7621_CLK_I2C, "i2c", "50m", BIT(16)), + GATE(MT7621_CLK_I2S, "i2s", "270m", BIT(17)), + GATE(MT7621_CLK_SPI, "spi", "bus", BIT(18)), + GATE(MT7621_CLK_UART1, "uart1", "50m", BIT(19)), + GATE(MT7621_CLK_UART2, "uart2", "50m", BIT(20)), + GATE(MT7621_CLK_UART3, "uart3", "50m", BIT(21)), + GATE(MT7621_CLK_ETH, "eth", "50m", BIT(23)), + GATE(MT7621_CLK_PCIE0, "pcie0", "125m", BIT(24)), + GATE(MT7621_CLK_PCIE1, "pcie1", "125m", BIT(25)), + GATE(MT7621_CLK_PCIE2, "pcie2", "125m", BIT(26)), + GATE(MT7621_CLK_CRYPTO, "crypto", "250m", BIT(29)), + GATE(MT7621_CLK_SHXC, "shxc", "50m", BIT(30)) +}; + +static inline struct mt7621_gate *to_mt7621_gate(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_gate, hw); +} + +static int mt7621_gate_enable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + return regmap_update_bits(scon, SYSC_REG_CLKCFG1, + clk_gate->bit_idx, clk_gate->bit_idx); +} + +static void mt7621_gate_disable(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + + regmap_update_bits(scon, SYSC_REG_CLKCFG1, clk_gate->bit_idx, 0); +} + +static int mt7621_gate_is_enabled(struct clk_hw *hw) +{ + struct mt7621_gate *clk_gate = to_mt7621_gate(hw); + struct regmap *scon = clk_gate->clk_prov->syscon_regmap; + unsigned int val; + + if (regmap_read(scon, SYSC_REG_CLKCFG1, &val)) + return 0; + + return val & clk_gate->bit_idx; +} + +static const struct clk_ops mt7621_gate_ops = { + .enable = mt7621_gate_enable, + .disable = mt7621_gate_disable, + .is_enabled = mt7621_gate_is_enabled, +}; + +static int mt7621_gate_ops_init(struct device_node *np, + struct mt7621_gate *sclk) +{ + struct clk_init_data init = { + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + .num_parents = 1, + .parent_names = &sclk->parent_name, + .ops = &mt7621_gate_ops, + .name = sclk->name, + }; + + sclk->hw.init = &init; + return of_clk_hw_register(np, &sclk->hw); +} + +static int mt7621_register_gates(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + sclk->clk_prov = clk_prov; + ret = mt7621_gate_ops_init(clk_prov->node, sclk); + if (ret) { + pr_err("Couldn't register clock %s\n", sclk->name); + goto err_clk_unreg; + } + + hws[sclk->idx] = &sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + clk_hw_unregister(&sclk->hw); + } + return ret; +} + +#define FIXED(_id, _name, _pname, _rate) \ + { \ + .idx = _id, \ + .name = _name, \ + .parent_name = _pname, \ + .clk_prov = NULL, \ + .rate = _rate \ + } + +static struct mt7621_fixed_clk mt7621_fixed_clks[] = { + FIXED(MT7621_CLK_50M, "50m", "xtal", MHZ(50)), + FIXED(MT7621_CLK_125M, "125m", "xtal", MHZ(125)), + FIXED(MT7621_CLK_150M, "150m", "xtal", MHZ(150)), + FIXED(MT7621_CLK_250M, "250m", "xtal", MHZ(250)), + FIXED(MT7621_CLK_270M, "270m", "xtal", MHZ(270)), +}; + +static int mt7621_register_fixed_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + sclk->clk_prov = clk_prov; + sclk->hw = clk_hw_register_fixed_rate(NULL, sclk->name, + sclk->parent_name, 0, + sclk->rate); + if (IS_ERR(sclk->hw)) { + pr_err("Couldn't register clock %s\n", sclk->name); + ret = PTR_ERR(sclk->hw); + goto err_clk_unreg; + } + + hws[sclk->idx] = sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + clk_hw_unregister_fixed_rate(sclk->hw); + } + return ret; +} + +static inline struct mt7621_clk *to_mt7621_clk(struct clk_hw *hw) +{ + return container_of(hw, struct mt7621_clk, hw); +} + +static unsigned long mt7621_xtal_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 val; + + regmap_read(scon, SYSC_REG_SYSTEM_CONFIG0, &val); + val = (val >> XTAL_MODE_SEL_SHIFT) & XTAL_MODE_SEL_MASK; + + if (val <= 2) + return MHZ(20); + else if (val <= 5) + return MHZ(40); + + return MHZ(25); +} + +static unsigned long mt7621_cpu_recalc_rate(struct clk_hw *hw, + unsigned long xtal_clk) +{ + static const u32 prediv_tbl[] = { 0, 1, 2, 2 }; + struct mt7621_clk *clk = to_mt7621_clk(hw); + struct regmap *scon = clk->clk_prov->syscon_regmap; + u32 clkcfg, clk_sel, curclk, ffiv, ffrac; + u32 pll, prediv, fbdiv; + unsigned long cpu_clk; + + regmap_read(scon, SYSC_REG_CLKCFG0, &clkcfg); + clk_sel = (clkcfg >> CPU_CLK_SEL_SHIFT) & CPU_CLK_SEL_MASK; + + regmap_read(scon, SYSC_REG_CUR_CLK_STS, &curclk); + ffiv = (curclk >> CUR_CPU_FDIV_SHIFT) & CUR_CPU_FDIV_MASK; + ffrac = (curclk >> CUR_CPU_FFRAC_SHIFT) & CUR_CPU_FFRAC_MASK; + + switch (clk_sel) { + case 0: + cpu_clk = MHZ(500); + break; + case 1: + pll = rt_memc_r32(MEMC_REG_CPU_PLL); + fbdiv = (pll >> CPU_PLL_FBDIV_SHIFT) & CPU_PLL_FBDIV_MASK; + prediv = (pll >> CPU_PLL_PREDIV_SHIFT) & CPU_PLL_PREDIV_MASK; + cpu_clk = ((fbdiv + 1) * xtal_clk) >> prediv_tbl[prediv]; + break; + default: + cpu_clk = xtal_clk; + } + + return cpu_clk / ffiv * ffrac; +} + +static unsigned long mt7621_bus_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return parent_rate / 4; +} + +#define CLK_BASE(_name, _parent, _recalc) { \ + .init = &(struct clk_init_data) { \ + .name = _name, \ + .ops = &(const struct clk_ops) { \ + .recalc_rate = _recalc, \ + }, \ + .parent_names = (const char *const[]) { _parent }, \ + .num_parents = _parent ? 1 : 0 \ + }, \ +} + +static struct mt7621_clk mt7621_clks_base[] = { + { NULL, CLK_BASE("xtal", NULL, mt7621_xtal_recalc_rate) }, + { NULL, CLK_BASE("cpu", "xtal", mt7621_cpu_recalc_rate) }, + { NULL, CLK_BASE("bus", "cpu", mt7621_bus_recalc_rate) }, +}; + +static int mt7621_register_top_clocks(struct mt7621_clk_provider *clk_prov) +{ + struct clk_hw_onecell_data **clk_data = &clk_prov->clk_data; + struct clk_hw **hws = (*clk_data)->hws; + int ret, i; + + for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + sclk->clk_prov = clk_prov; + ret = of_clk_hw_register(clk_prov->node, &sclk->hw); + if (ret) { + pr_err("Couldn't register top clock %i\n", i); + goto err_clk_unreg; + } + + hws[i] = &sclk->hw; + (*clk_data)->num++; + } + + return 0; + +err_clk_unreg: + while (--i >= 0) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + clk_hw_unregister(&sclk->hw); + } + return ret; +} + +static void __init mt7621_clk_init(struct device_node *node) +{ + struct mt7621_clk_provider *clk_prov; + struct clk_hw_onecell_data **clk_data; + int i, ret, count; + + clk_prov = kzalloc(sizeof(*clk_prov), GFP_KERNEL); + if (!clk_prov) + return; + + clk_prov->syscon_regmap = syscon_node_to_regmap(node->parent); + if (IS_ERR(clk_prov->syscon_regmap)) { + pr_err("Could not get syscon regmap\n"); + goto free_clk_prov; + } + + clk_prov->node = node; + + clk_data = &clk_prov->clk_data; + count = ARRAY_SIZE(mt7621_clks_base) + + ARRAY_SIZE(mt7621_fixed_clks) + ARRAY_SIZE(mt7621_gates); + *clk_data = kzalloc(struct_size(*clk_data, hws, count), GFP_KERNEL); + if (!*clk_data) + goto free_clk_prov; + + ret = mt7621_register_top_clocks(clk_prov); + if (ret) { + pr_err("Couldn't register top clocks\n"); + goto free_clk_data; + } + + ret = mt7621_register_fixed_clocks(clk_prov); + if (ret) { + pr_err("Couldn't register fixed clocks\n"); + goto unreg_clk_top; + } + + ret = mt7621_register_gates(clk_prov); + if (ret) { + pr_err("Couldn't register fixed clock gates\n"); + goto unreg_clk_fixed; + } + + ret = of_clk_add_hw_provider(node, of_clk_hw_onecell_get, + clk_prov->clk_data); + if (ret) { + pr_err("Couldn't add clk hw provider\n"); + goto unreg_clk_gates; + } + + return; + +unreg_clk_gates: + for (i = 0; i < ARRAY_SIZE(mt7621_gates); i++) { + struct mt7621_gate *sclk = &mt7621_gates[i]; + + clk_hw_unregister(&sclk->hw); + } + +unreg_clk_fixed: + for (i = 0; i < ARRAY_SIZE(mt7621_fixed_clks); i++) { + struct mt7621_fixed_clk *sclk = &mt7621_fixed_clks[i]; + + clk_hw_unregister_fixed_rate(sclk->hw); + } + +unreg_clk_top: + for (i = 0; i < ARRAY_SIZE(mt7621_clks_base); i++) { + struct mt7621_clk *sclk = &mt7621_clks_base[i]; + + clk_hw_unregister(&sclk->hw); + } + +free_clk_data: + kfree(clk_prov->clk_data); + +free_clk_prov: + kfree(clk_prov); +} + +CLK_OF_DECLARE(mt7621_clk, "mediatek,mt7621-clk", mt7621_clk_init); + +MODULE_AUTHOR("Sergio Paracuellos "); +MODULE_DESCRIPTION("Mediatek Mt7621 clock driver"); +MODULE_LICENSE("GPL v2"); -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:54 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:54 +0100 Subject: [PATCH v4 4/6] staging: mt7621-dts: make use of new 'mt7621-clk' In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-5-sergio.paracuellos@gmail.com> Clocks for SoC mt7621 have been properly integrated so there is no need to declare fixed clocks at all in the device tree. Remove all of them, add new device tree nodes for mt7621-clk and update the rest of the nodes to use them. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-dts/gbpc1.dts | 11 ---- drivers/staging/mt7621-dts/mt7621.dtsi | 75 ++++++++++++-------------- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/drivers/staging/mt7621-dts/gbpc1.dts b/drivers/staging/mt7621-dts/gbpc1.dts index a7c0d3115d72..7716d0efe524 100644 --- a/drivers/staging/mt7621-dts/gbpc1.dts +++ b/drivers/staging/mt7621-dts/gbpc1.dts @@ -100,17 +100,6 @@ partition at 50000 { }; }; -&sysclock { - compatible = "fixed-clock"; - /* This is normally 1/4 of cpuclock */ - clock-frequency = <225000000>; -}; - -&cpuclock { - compatible = "fixed-clock"; - clock-frequency = <900000000>; -}; - &pcie { pinctrl-names = "default"; pinctrl-0 = <&pcie_pins>; diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 82aa93634eda..35cfda8f6faf 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -1,5 +1,6 @@ #include #include +#include / { #address-cells = <1>; @@ -27,27 +28,6 @@ aliases { serial0 = &uartlite; }; - cpuclock: cpuclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* FIXME: there should be way to detect this */ - clock-frequency = <880000000>; - }; - - sysclock: sysclock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - - /* This is normally 1/4 of cpuclock */ - clock-frequency = <220000000>; - }; - - mmc_clock: mmc_clock at 0 { - #clock-cells = <0>; - compatible = "fixed-clock"; - clock-frequency = <48000000>; - }; mmc_fixed_3v3: fixedregulator at 0 { compatible = "regulator-fixed"; @@ -76,8 +56,16 @@ palmbus: palmbus at 1E000000 { #size-cells = <1>; sysc: sysc at 0 { - compatible = "mtk,mt7621-sysc"; + compatible = "mtk,mt7621-sysc", "syscon"; reg = <0x0 0x100>; + + pll: pll { + compatible = "mediatek,mt7621-clk"; + #clock-cells = <1>; + clock-output-names = "xtal", "cpu", "bus", + "50m", "125m", "150m", + "250m", "270m"; + }; }; wdt: wdt at 100 { @@ -100,8 +88,8 @@ i2c: i2c at 900 { compatible = "mediatek,mt7621-i2c"; reg = <0x900 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2C>; + clock-names = "i2c"; resets = <&rstctrl 16>; reset-names = "i2c"; @@ -118,8 +106,8 @@ i2s: i2s at a00 { compatible = "mediatek,mt7621-i2s"; reg = <0xa00 0x100>; - clocks = <&sysclock>; - + clocks = <&pll MT7621_CLK_I2S>; + clock-names = "i2s"; resets = <&rstctrl 17>; reset-names = "i2s"; @@ -155,8 +143,8 @@ uartlite: uartlite at c00 { compatible = "ns16550a"; reg = <0xc00 0x100>; - clocks = <&sysclock>; - clock-frequency = <50000000>; + clocks = <&pll MT7621_CLK_UART1>; + clock-names = "uart1"; interrupt-parent = <&gic>; interrupts = ; @@ -172,7 +160,8 @@ spi0: spi at b00 { compatible = "ralink,mt7621-spi"; reg = <0xb00 0x100>; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_SPI>; + clock-names = "spi"; resets = <&rstctrl 18>; reset-names = "spi"; @@ -188,6 +177,8 @@ gdma: gdma at 2800 { compatible = "ralink,rt3883-gdma"; reg = <0x2800 0x800>; + clocks = <&pll MT7621_CLK_GDMA>; + clock-names = "gdma"; resets = <&rstctrl 14>; reset-names = "dma"; @@ -205,6 +196,8 @@ hsdma: hsdma at 7000 { compatible = "mediatek,mt7621-hsdma"; reg = <0x7000 0x1000>; + clocks = <&pll MT7621_CLK_HSDMA>; + clock-names = "hsdma"; resets = <&rstctrl 5>; reset-names = "hsdma"; @@ -315,11 +308,6 @@ rstctrl: rstctrl { #reset-cells = <1>; }; - clkctrl: clkctrl { - compatible = "ralink,rt2880-clock"; - #clock-cells = <1>; - }; - sdhci: sdhci at 1E130000 { status = "disabled"; @@ -338,7 +326,8 @@ sdhci: sdhci at 1E130000 { pinctrl-0 = <&sdhci_pins>; pinctrl-1 = <&sdhci_pins>; - clocks = <&mmc_clock &mmc_clock>; + clocks = <&pll MT7621_CLK_SHXC>, + <&pll MT7621_CLK_50M>; clock-names = "source", "hclk"; interrupt-parent = <&gic>; @@ -353,7 +342,7 @@ xhci: xhci at 1E1C0000 { 0x1e1d0700 0x0100>; reg-names = "mac", "ippc"; - clocks = <&sysclock>; + clocks = <&pll MT7621_CLK_XTAL>; clock-names = "sys_ck"; interrupt-parent = <&gic>; @@ -372,7 +361,7 @@ gic: interrupt-controller at 1fbc0000 { timer { compatible = "mti,gic-timer"; interrupts = ; - clocks = <&cpuclock>; + clocks = <&pll MT7621_CLK_CPU>; }; }; @@ -385,6 +374,9 @@ nand: nand at 1e003000 { 0x1e003800 0x800>; #address-cells = <1>; #size-cells = <1>; + + clocks = <&pll MT7621_CLK_NAND>; + clock-names = "nand"; }; ethsys: syscon at 1e000000 { @@ -398,8 +390,9 @@ ethernet: ethernet at 1e100000 { compatible = "mediatek,mt7621-eth"; reg = <0x1e100000 0x10000>; - clocks = <&sysclock>; - clock-names = "ethif"; + clocks = <&pll MT7621_CLK_FE>, + <&pll MT7621_CLK_ETH>; + clock-names = "fe", "ethif"; #address-cells = <1>; #size-cells = <0>; @@ -532,7 +525,9 @@ GIC_SHARED 24 IRQ_TYPE_LEVEL_HIGH resets = <&rstctrl 24 &rstctrl 25 &rstctrl 26>; reset-names = "pcie0", "pcie1", "pcie2"; - clocks = <&clkctrl 24 &clkctrl 25 &clkctrl 26>; + clocks = <&pll MT7621_CLK_PCIE0>, + <&pll MT7621_CLK_PCIE1>, + <&pll MT7621_CLK_PCIE2>; clock-names = "pcie0", "pcie1", "pcie2"; phys = <&pcie0_phy 1>, <&pcie2_phy 0>; phy-names = "pcie-phy0", "pcie-phy2"; -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:56 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:56 +0100 Subject: [PATCH v4 6/6] MAINTAINERS: add MT7621 CLOCK maintainer In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-7-sergio.paracuellos@gmail.com> Adding myself as maintainer for mt7621 clock driver. Signed-off-by: Sergio Paracuellos --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f1f088a29bc2..30822ad6837c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11142,6 +11142,12 @@ L: linux-wireless at vger.kernel.org S: Maintained F: drivers/net/wireless/mediatek/mt7601u/ +MEDIATEK MT7621 CLOCK DRIVER +M: Sergio Paracuellos +S: Maintained +F: Documentation/devicetree/bindings/clock/mediatek,mt7621-clk.yaml +F: drivers/clk/ralink/clk-mt7621.c + MEDIATEK MT7621/28/88 I2C DRIVER M: Stefan Roese L: linux-i2c at vger.kernel.org -- 2.25.1 From sergio.paracuellos at gmail.com Sun Nov 22 09:55:55 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Sun, 22 Nov 2020 10:55:55 +0100 Subject: [PATCH v4 5/6] staging: mt7621-dts: use valid vendor 'mediatek' instead of invalid 'mtk' In-Reply-To: <20201122095556.21597-1-sergio.paracuellos@gmail.com> References: <20201122095556.21597-1-sergio.paracuellos@gmail.com> Message-ID: <20201122095556.21597-6-sergio.paracuellos@gmail.com> Vendor listed for mediatek in kernel vendor file 'vendor-prefixes.yaml' contains 'mediatek' as a valid vendor string. Some nodes in the device tree are using an invalid vendor string vfor 'mtk' instead. Fix all of them in dts file. Update also ralink mt7621 related code to properly match new strings. Even there are used in the device tree there are some strings that are not referred anywhere but have been also updated with new vendor name. These are 'mtk,mt7621-wdt', 'mtk,mt7621-nand', 'mtk,mt7621-mc', and 'mtk,mt7621-cpc'. Signed-off-by: Sergio Paracuellos --- arch/mips/ralink/mt7621.c | 6 +++--- drivers/staging/mt7621-dts/mt7621.dtsi | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/mips/ralink/mt7621.c b/arch/mips/ralink/mt7621.c index ca0ac607b0f3..5d74fc1c96ac 100644 --- a/arch/mips/ralink/mt7621.c +++ b/arch/mips/ralink/mt7621.c @@ -112,8 +112,8 @@ phys_addr_t mips_cpc_default_phys_base(void) void __init ralink_of_remap(void) { - rt_sysc_membase = plat_of_remap_node("mtk,mt7621-sysc"); - rt_memc_membase = plat_of_remap_node("mtk,mt7621-memc"); + rt_sysc_membase = plat_of_remap_node("mediatek,mt7621-sysc"); + rt_memc_membase = plat_of_remap_node("mediatek,mt7621-memc"); if (!rt_sysc_membase || !rt_memc_membase) panic("Failed to remap core resources"); @@ -181,7 +181,7 @@ void prom_soc_init(struct ralink_soc_info *soc_info) if (n0 == MT7621_CHIP_NAME0 && n1 == MT7621_CHIP_NAME1) { name = "MT7621"; - soc_info->compatible = "mtk,mt7621-soc"; + soc_info->compatible = "mediatek,mt7621-soc"; } else { panic("mt7621: unknown SoC, n0:%08x n1:%08x\n", n0, n1); } diff --git a/drivers/staging/mt7621-dts/mt7621.dtsi b/drivers/staging/mt7621-dts/mt7621.dtsi index 35cfda8f6faf..8fc311703beb 100644 --- a/drivers/staging/mt7621-dts/mt7621.dtsi +++ b/drivers/staging/mt7621-dts/mt7621.dtsi @@ -56,7 +56,7 @@ palmbus: palmbus at 1E000000 { #size-cells = <1>; sysc: sysc at 0 { - compatible = "mtk,mt7621-sysc", "syscon"; + compatible = "mediatek,mt7621-sysc", "syscon"; reg = <0x0 0x100>; pll: pll { @@ -69,7 +69,7 @@ pll: pll { }; wdt: wdt at 100 { - compatible = "mtk,mt7621-wdt"; + compatible = "mediatek,mt7621-wdt"; reg = <0x100 0x100>; }; @@ -125,17 +125,17 @@ i2s: i2s at a00 { }; memc: memc at 5000 { - compatible = "mtk,mt7621-memc"; + compatible = "mediatek,mt7621-memc"; reg = <0x5000 0x1000>; }; cpc: cpc at 1fbf0000 { - compatible = "mtk,mt7621-cpc"; + compatible = "mediatek,mt7621-cpc"; reg = <0x1fbf0000 0x8000>; }; mc: mc at 1fbf8000 { - compatible = "mtk,mt7621-mc"; + compatible = "mediatek,mt7621-mc"; reg = <0x1fbf8000 0x8000>; }; @@ -368,7 +368,7 @@ timer { nand: nand at 1e003000 { status = "disabled"; - compatible = "mtk,mt7621-nand"; + compatible = "mediatek,mt7621-nand"; bank-width = <2>; reg = <0x1e003000 0x800 0x1e003800 0x800>; -- 2.25.1 From gregkh at linuxfoundation.org Sun Nov 22 11:43:14 2020 From: gregkh at linuxfoundation.org (Greg KH) Date: Sun, 22 Nov 2020 12:43:14 +0100 Subject: [GIT PULL] Staging/IIO driver fixes for 5.10-rc5 Message-ID: The following changes since commit 3cea11cd5e3b00d91caf0b4730194039b45c5891: Linux 5.10-rc2 (2020-11-01 14:43:51 -0800) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git tags/staging-5.10-rc5 for you to fetch changes up to 2dde2821b57f12fa8601d35d438b5e300fcbbe1d: Merge tag 'iio-fixes-for-5.10a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-linus (2020-11-17 10:53:00 +0100) ---------------------------------------------------------------- Staging/IIO fixes for 5.10-rc5 Here are some small Staging and IIO driver fixes for 5.10-rc5. They include: - IIO fixes for reported regressions and problems - new device ids for IIO drivers - new device id for rtl8723bs driver - staging ralink driver Kconfig dependency fix - staging mt7621-pci bus resource fix All of these have been in linux-next all week with no reported issues. Signed-off-by: Greg Kroah-Hartman ---------------------------------------------------------------- Brian O'Keefe (1): staging: rtl8723bs: Add 024c:0627 to the list of SDIO device-ids David Lechner (1): counter/ti-eqep: Fix regmap max_register Fabien Parent (1): iio: adc: mediatek: fix unset field Fabrice Gasnier (1): docs: ABI: testing: iio: stm32: remove re-introduced unsupported ABI Greg Kroah-Hartman (1): Merge tag 'iio-fixes-for-5.10a' of https://git.kernel.org/.../jic23/iio into staging-linus Gwendal Grignou (1): iio: cros_ec: Use default frequencies when EC returns invalid information Hans de Goede (2): iio: accel: kxcjk1013: Replace is_smo8500_device with an acpi_type enum iio: accel: kxcjk1013: Add support for KIOX010A ACPI DSM for setting tablet-mode Lorenzo Bianconi (1): iio: imu: st_lsm6dsx: set 10ms as min shub slave timeout Necip Fazil Yildiran (2): staging: ralink-gdma: fix kconfig dependency bug for DMA_RALINK iio: light: fix kconfig dependency bug for VCNL4035 Olivier Moysan (1): iio: adc: stm32-adc: fix a regression when using dma and irq Paul Cercueil (2): iio/adc: ingenic: Fix battery VREF for JZ4770 SoC iio/adc: ingenic: Fix AUX/VBAT readings when touchscreen is used Sergio Paracuellos (1): staging: mt7621-pci: avoid to request pci bus resources .../ABI/testing/sysfs-bus-iio-timer-stm32 | 24 ---------- drivers/counter/ti-eqep.c | 4 +- drivers/iio/accel/kxcjk-1013.c | 51 +++++++++++++++++++--- drivers/iio/adc/ingenic-adc.c | 34 ++++++++++++--- drivers/iio/adc/mt6577_auxadc.c | 6 ++- drivers/iio/adc/stm32-adc-core.c | 41 ++++++++--------- drivers/iio/adc/stm32-adc.c | 50 ++++++++++++++++++++- .../common/cros_ec_sensors/cros_ec_sensors_core.c | 16 ++++--- drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c | 6 ++- drivers/iio/light/Kconfig | 1 + drivers/staging/mt7621-pci/pci-mt7621.c | 15 ++----- drivers/staging/ralink-gdma/Kconfig | 1 + drivers/staging/rtl8723bs/os_dep/sdio_intf.c | 1 + 13 files changed, 165 insertions(+), 85 deletions(-) From keescook at chromium.org Sun Nov 22 16:17:03 2020 From: keescook at chromium.org (Kees Cook) Date: Sun, 22 Nov 2020 08:17:03 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: <202011220816.8B6591A@keescook> On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > On Fri, 20 Nov 2020 11:30:40 -0800 Kees Cook wrote: > > On Fri, Nov 20, 2020 at 10:53:44AM -0800, Jakub Kicinski wrote: > > > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > > > > This series aims to fix almost all remaining fall-through warnings in > > > > order to enable -Wimplicit-fallthrough for Clang. > > > > > > > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > > > > add multiple break/goto/return/fallthrough statements instead of just > > > > letting the code fall through to the next case. > > > > > > > > Notice that in order to enable -Wimplicit-fallthrough for Clang, this > > > > change[1] is meant to be reverted at some point. So, this patch helps > > > > to move in that direction. > > > > > > > > Something important to mention is that there is currently a discrepancy > > > > between GCC and Clang when dealing with switch fall-through to empty case > > > > statements or to cases that only contain a break/continue/return > > > > statement[2][3][4]. > > > > > > Are we sure we want to make this change? Was it discussed before? > > > > > > Are there any bugs Clangs puritanical definition of fallthrough helped > > > find? > > > > > > IMVHO compiler warnings are supposed to warn about issues that could > > > be bugs. Falling through to default: break; can hardly be a bug?! > > > > It's certainly a place where the intent is not always clear. I think > > this makes all the cases unambiguous, and doesn't impact the machine > > code, since the compiler will happily optimize away any behavioral > > redundancy. > > If none of the 140 patches here fix a real bug, and there is no change > to machine code then it sounds to me like a W=2 kind of a warning. FWIW, this series has found at least one bug so far: https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ -- Kees Cook From mchehab+huawei at kernel.org Sun Nov 22 16:32:14 2020 From: mchehab+huawei at kernel.org (Mauro Carvalho Chehab) Date: Sun, 22 Nov 2020 17:32:14 +0100 Subject: [PATCH 094/141] media: atomisp: Fix fall-through warnings for Clang In-Reply-To: <6a1c9b29a2d8e5accb48cd179cfe43b87fd83a00.1605896060.git.gustavoars@kernel.org> References: <6a1c9b29a2d8e5accb48cd179cfe43b87fd83a00.1605896060.git.gustavoars@kernel.org> Message-ID: <20201122173214.2a052066@coco.lan> Em Fri, 20 Nov 2020 12:36:50 -0600 "Gustavo A. R. Silva" escreveu: > In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning > by explicitly adding a break statement instead of letting the code fall > through to the next case. > > Link: https://github.com/KSPP/linux/issues/115 > Signed-off-by: Gustavo A. R. Silva Reviewed-by: Mauro Carvalho Chehab > --- > drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c > index b4813cd50daa..4a18da6bf0c1 100644 > --- a/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c > +++ b/drivers/staging/media/atomisp/pci/runtime/isys/src/rx.c > @@ -368,6 +368,7 @@ static mipi_predictor_t sh_css_csi2_compression_type_2_mipi_predictor( > break; > case IA_CSS_CSI2_COMPRESSION_TYPE_2: > predictor = MIPI_PREDICTOR_TYPE2 - 1; > + break; > default: > break; > } Thanks, Mauro From James.Bottomley at HansenPartnership.com Sun Nov 22 18:21:59 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Sun, 22 Nov 2020 10:21:59 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <202011220816.8B6591A@keescook> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> Message-ID: <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> On Sun, 2020-11-22 at 08:17 -0800, Kees Cook wrote: > On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > > On Fri, 20 Nov 2020 11:30:40 -0800 Kees Cook wrote: > > > On Fri, Nov 20, 2020 at 10:53:44AM -0800, Jakub Kicinski wrote: > > > > On Fri, 20 Nov 2020 12:21:39 -0600 Gustavo A. R. Silva wrote: > > > > > This series aims to fix almost all remaining fall-through > > > > > warnings in order to enable -Wimplicit-fallthrough for Clang. > > > > > > > > > > In preparation to enable -Wimplicit-fallthrough for Clang, > > > > > explicitly add multiple break/goto/return/fallthrough > > > > > statements instead of just letting the code fall through to > > > > > the next case. > > > > > > > > > > Notice that in order to enable -Wimplicit-fallthrough for > > > > > Clang, this change[1] is meant to be reverted at some point. > > > > > So, this patch helps to move in that direction. > > > > > > > > > > Something important to mention is that there is currently a > > > > > discrepancy between GCC and Clang when dealing with switch > > > > > fall-through to empty case statements or to cases that only > > > > > contain a break/continue/return statement[2][3][4]. > > > > > > > > Are we sure we want to make this change? Was it discussed > > > > before? > > > > > > > > Are there any bugs Clangs puritanical definition of fallthrough > > > > helped find? > > > > > > > > IMVHO compiler warnings are supposed to warn about issues that > > > > could be bugs. Falling through to default: break; can hardly be > > > > a bug?! > > > > > > It's certainly a place where the intent is not always clear. I > > > think this makes all the cases unambiguous, and doesn't impact > > > the machine code, since the compiler will happily optimize away > > > any behavioral redundancy. > > > > If none of the 140 patches here fix a real bug, and there is no > > change to machine code then it sounds to me like a W=2 kind of a > > warning. > > FWIW, this series has found at least one bug so far: > https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ Well, it's a problem in an error leg, sure, but it's not a really compelling reason for a 141 patch series, is it? All that fixing this error will do is get the driver to print "oh dear there's a problem" under four more conditions than it previously did. We've been at this for three years now with nearly a thousand patches, firstly marking all the fall throughs with /* fall through */ and later changing it to fallthrough. At some point we do have to ask if the effort is commensurate with the protection afforded. Please tell me our reward for all this effort isn't a single missing error print. James From joe at perches.com Sun Nov 22 18:25:37 2020 From: joe at perches.com (Joe Perches) Date: Sun, 22 Nov 2020 10:25:37 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> Message-ID: On Sun, 2020-11-22 at 10:21 -0800, James Bottomley wrote: > Please tell me > our reward for all this effort isn't a single missing error print. There were quite literally dozens of logical defects found by the fallthrough additions. Very few were logging only. From James.Bottomley at HansenPartnership.com Sun Nov 22 19:12:30 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Sun, 22 Nov 2020 11:12:30 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> Message-ID: <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> On Sun, 2020-11-22 at 10:25 -0800, Joe Perches wrote: > On Sun, 2020-11-22 at 10:21 -0800, James Bottomley wrote: > > Please tell me our reward for all this effort isn't a single > > missing error print. > > There were quite literally dozens of logical defects found > by the fallthrough additions. Very few were logging only. So can you give us the best examples (or indeed all of them if someone is keeping score)? hopefully this isn't a US election situation ... James From joe at perches.com Sun Nov 22 19:22:47 2020 From: joe at perches.com (Joe Perches) Date: Sun, 22 Nov 2020 11:22:47 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> Message-ID: On Sun, 2020-11-22 at 11:12 -0800, James Bottomley wrote: > On Sun, 2020-11-22 at 10:25 -0800, Joe Perches wrote: > > On Sun, 2020-11-22 at 10:21 -0800, James Bottomley wrote: > > > Please tell me our reward for all this effort isn't a single > > > missing error print. > > > > There were quite literally dozens of logical defects found > > by the fallthrough additions. Very few were logging only. > > So can you give us the best examples (or indeed all of them if someone > is keeping score)? hopefully this isn't a US election situation ... Gustavo? Are you running for congress now? https://lwn.net/Articles/794944/ From James.Bottomley at HansenPartnership.com Sun Nov 22 19:53:55 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Sun, 22 Nov 2020 11:53:55 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> Message-ID: On Sun, 2020-11-22 at 11:22 -0800, Joe Perches wrote: > On Sun, 2020-11-22 at 11:12 -0800, James Bottomley wrote: > > On Sun, 2020-11-22 at 10:25 -0800, Joe Perches wrote: > > > On Sun, 2020-11-22 at 10:21 -0800, James Bottomley wrote: > > > > Please tell me our reward for all this effort isn't a single > > > > missing error print. > > > > > > There were quite literally dozens of logical defects found > > > by the fallthrough additions. Very few were logging only. > > > > So can you give us the best examples (or indeed all of them if > > someone is keeping score)? hopefully this isn't a US election > > situation ... > > Gustavo? Are you running for congress now? > > https://lwn.net/Articles/794944/ That's 21 reported fixes of which about 50% seem to produce no change in code behaviour at all, a quarter seem to have no user visible effect with the remaining quarter producing unexpected errors on obscure configuration parameters, which is why no-one really noticed them before. James From miguel.ojeda.sandonis at gmail.com Sun Nov 22 20:35:58 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Sun, 22 Nov 2020 21:35:58 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> Message-ID: On Sun, Nov 22, 2020 at 7:22 PM James Bottomley wrote: > > Well, it's a problem in an error leg, sure, but it's not a really > compelling reason for a 141 patch series, is it? All that fixing this > error will do is get the driver to print "oh dear there's a problem" > under four more conditions than it previously did. > > We've been at this for three years now with nearly a thousand patches, > firstly marking all the fall throughs with /* fall through */ and later > changing it to fallthrough. At some point we do have to ask if the > effort is commensurate with the protection afforded. Please tell me > our reward for all this effort isn't a single missing error print. It isn't that much effort, isn't it? Plus we need to take into account the future mistakes that it might prevent, too. So even if there were zero problems found so far, it is still a positive change. I would agree if these changes were high risk, though; but they are almost trivial. Cheers, Miguel From pr-tracker-bot at kernel.org Sun Nov 22 21:09:11 2020 From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org) Date: Sun, 22 Nov 2020 21:09:11 +0000 Subject: [GIT PULL] Staging/IIO driver fixes for 5.10-rc5 In-Reply-To: References: Message-ID: <160607935141.25428.2616061909480561844.pr-tracker-bot@kernel.org> The pull request you sent on Sun, 22 Nov 2020 12:43:14 +0100: > git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git tags/staging-5.10-rc5 has been merged into torvalds/linux.git: https://git.kernel.org/torvalds/c/d27637ece80f25124e0e6871b7b6cb855e1c670c Thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/prtracker.html From adelinazeuki at gmail.com Sun Nov 22 21:48:57 2020 From: adelinazeuki at gmail.com (Adelina Zeuki) Date: Sun, 22 Nov 2020 21:48:57 +0000 Subject: Hello !! Message-ID: <5fbadcd3.1c69fb81.8dfc7.11b6@mx.google.com> Hi dear, Can i talk with you ? From anglicaramose at gmail.com Sun Nov 22 21:54:08 2020 From: anglicaramose at gmail.com (Adelina Zeuki) Date: Sun, 22 Nov 2020 21:54:08 +0000 Subject: Hello !! Message-ID: <5fbade0c.1c69fb81.9b3f2.1056@mx.google.com> Hi dear, Can i talk with you ? From sam at ravnborg.org Sun Nov 22 22:10:40 2020 From: sam at ravnborg.org (Sam Ravnborg) Date: Sun, 22 Nov 2020 23:10:40 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> Message-ID: <20201122221040.GD566387@ravnborg.org> Hi James. > > > If none of the 140 patches here fix a real bug, and there is no > > > change to machine code then it sounds to me like a W=2 kind of a > > > warning. > > > > FWIW, this series has found at least one bug so far: > > https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ > > > Well, it's a problem in an error leg, sure, but it's not a really > compelling reason for a 141 patch series, is it? All that fixing this > error will do is get the driver to print "oh dear there's a problem" > under four more conditions than it previously did. You are asking the wrong question here. Yuo should ask how many hours could have been saved by all the bugs people have been fighting with and then fixed *before* the code hit the kernel at all. My personal experience is that I, more than once, have had errors related to a missing break in my code. So this warnings is IMO a win. And if we are only ~100 patches to have it globally enabled then it is a no-brainer in my book. Sam From James.Bottomley at HansenPartnership.com Sun Nov 22 22:36:00 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Sun, 22 Nov 2020 14:36:00 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> Message-ID: <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> On Sun, 2020-11-22 at 21:35 +0100, Miguel Ojeda wrote: > On Sun, Nov 22, 2020 at 7:22 PM James Bottomley > wrote: > > Well, it's a problem in an error leg, sure, but it's not a really > > compelling reason for a 141 patch series, is it? All that fixing > > this error will do is get the driver to print "oh dear there's a > > problem" under four more conditions than it previously did. > > > > We've been at this for three years now with nearly a thousand > > patches, firstly marking all the fall throughs with /* fall through > > */ and later changing it to fallthrough. At some point we do have > > to ask if the effort is commensurate with the protection > > afforded. Please tell me our reward for all this effort isn't a > > single missing error print. > > It isn't that much effort, isn't it? Well, it seems to be three years of someone's time plus the maintainer review time and series disruption of nearly a thousand patches. Let's be conservative and assume the producer worked about 30% on the series and it takes about 5-10 minutes per patch to review, merge and for others to rework existing series. So let's say it's cost a person year of a relatively junior engineer producing the patches and say 100h of review and application time. The latter is likely the big ticket item because it's what we have in least supply in the kernel (even though it's 20x vs the producer time). > Plus we need to take into account the future mistakes that it might > prevent, too. So even if there were zero problems found so far, it is > still a positive change. Well, the question I was asking is if it's worth the cost which I've tried to outline above. > I would agree if these changes were high risk, though; but they are > almost trivial. It's not about the risk of the changes it's about the cost of implementing them. Even if you discount the producer time (which someone gets to pay for, and if I were the engineering manager, I'd be unhappy about), the review/merge/rework time is pretty significant in exchange for six minor bug fixes. Fine, when a new compiler warning comes along it's certainly reasonable to see if we can benefit from it and the fact that the compiler people think it's worthwhile is enough evidence to assume this initially. But at some point you have to ask whether that assumption is supported by the evidence we've accumulated over the time we've been using it. And if the evidence doesn't support it perhaps it is time to stop the experiment. James From ezequiel at vanguardiasur.com.ar Mon Nov 23 03:07:57 2020 From: ezequiel at vanguardiasur.com.ar (Ezequiel Garcia) Date: Mon, 23 Nov 2020 00:07:57 -0300 Subject: [PATCH v5 2/4] staging: media: Introduce NVIDIA Tegra video decoder driver In-Reply-To: <5665b221-04d7-6be9-2377-8006b9563d4b@gmail.com> References: <3d565db80f8dccafd14224924305243b37b75a07.1513038011.git.digetx@gmail.com> <5665b221-04d7-6be9-2377-8006b9563d4b@gmail.com> Message-ID: On Sat, 21 Nov 2020 at 23:01, Dmitry Osipenko wrote: > > 22.11.2020 04:02, Ezequiel Garcia ?????: > > Hi Dmitry, > > > ... > >> +++ b/drivers/staging/media/tegra-vde/TODO > >> @@ -0,0 +1,4 @@ > >> +TODO: > >> + - Implement V4L2 API once it gains support for stateless decoders. > >> + > >> +Contact: Dmitry Osipenko > > > > The API for H264 stateless decoding is ready. > > See https://lkml.org/lkml/2020/11/18/795. > > Hello Ezequiel, > > Thank you for the notification! My last attempt at implementing V4L API > support was about a year ago and it stopped once I realized that there > is no userspace which uses that API. FFMPEG and chromium browser had > some kind of V4L support, but it all was oriented at downstream driver > stacks, and thus, not usable. Do you know what is the current status? > The bulk of the API, which relies on the stateless decoder interface [1], and H264 stateless V4L2 controls has been ready for some time now, and there are various implementations supporting it. Chromium supports it [2], and I've tested it on chromebooks, through chromeos builds. We haven't tried a non-chromeos build, and I would say it's quite some work. GStreamer support is available as well. See [3] which should work for the latest H264 controls (the ones being moved out of staging). LibreELEC developers maintain an Ffmpeg branch [4], I expect it will be updated for the latest H264 controls soon, and hopefully merged in mainline Ffmpeg. GStreamer and Ffmpeg are relatively straightforward to build and test. Thanks, Ezequiel [1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html [2] https://github.com/chromium/chromium/tree/master/media/gpu/v4l2 [3] https://gitlab.freedesktop.org/ezequielgarcia/gst-plugins-bad/-/tree/h264_stable_uapi [4] https://github.com/Kwiboo/FFmpeg/tree/v4l2-request-hwaccel-4.3. > > One minor comment below. > > > ... > >> + // PPS > >> + __u8 pic_init_qp; > >> + __u8 deblocking_filter_control_present_flag; > >> + __u8 constrained_intra_pred_flag; > >> + __u8 chroma_qp_index_offset; > >> + __u8 pic_order_present_flag; > >> + > > > > This seems to be bottom_field_pic_order_in_frame_present_flag, > > as there is no "pic_order_present_flag" syntax element. > > Correct, looks like I borrowed that name from the libvdpau API. > > https://vdpau.pages.freedesktop.org/libvdpau/struct_vdp_picture_info_h264.html#a405f7ef26ea76bb2c446e151062fc001 From rkuofungx1 at gmail.com Sun Nov 22 17:03:54 2020 From: rkuofungx1 at gmail.com (max) Date: Sun, 22 Nov 2020 09:03:54 -0800 Subject: Benachrichtigung der Gewinner !!!. Message-ID: <20201123034411.D7DC8851A4@fraxinus.osuosl.org> Benachrichtigung der Gewinner !!!. Ihre E-Mail-ID hat ? 150.000,00 Euro (ein hundertf?nfzigtausend Euro) in LottoMax International Charity program.Ref Well Sp gewonnen /179/0-39/44/4-07/ES.Lucky No.9 / 44/15/27 / 49.For Weitere Informationen und Antragsverfahren , benutzen Sie bitte unser Agent unten in Verbindung; National Post-Code Agency.S.L Mr.Jaime Sanchez E-mail: infocodesl at aol.com Mit Ihren vollst?ndigen Namen, Adresse, Alter, Beruf, Telefonnummern Senden Sie Ihre Antwort auf diese E-Mail: infocodesl at aol.com Hinweis: Dies ist eine internationale Lotterie-Programm. Dieser Eintrag wurde automatisch aus dem Englischen ins Deutschland ?bersetzt. Herzlichen Gl?ckwunsch ! ________________________ Winners Notification !!!. Your email ID has won ?150,000.00 euros (One hundred and fifty thousand EUR) in LottoMax International Charity program.Ref No Sp /179/0-39/44/4-07/ES.Lucky No.9/44/15/27/49.For more information and claim procedure, please contact our agent below; National PostCode Agency.S.L Mr.Jaime Sanchez E-mail:infocodesl at aol.com With your full name, address, age, occupation, phone numbers Send your answer to this e-mail:infocodesl at aol.com Note: This is an international lottery program. Congratulations! From wens at csie.org Mon Nov 23 04:46:34 2020 From: wens at csie.org (Chen-Yu Tsai) Date: Mon, 23 Nov 2020 12:46:34 +0800 Subject: [PATCH v3 5/6] dt-bindings: media: cedrus: Add V3s compatible In-Reply-To: <20201116125617.7597-6-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> <20201116125617.7597-6-m.cerveny@computer.org> Message-ID: On Mon, Nov 16, 2020 at 8:58 PM Martin Cerveny wrote: > > Allwinner V3s SoC contains video engine. Add compatible for it. > > Signed-off-by: Martin Cerveny Acked-by: Chen-Yu Tsai From wens at csie.org Mon Nov 23 04:47:32 2020 From: wens at csie.org (Chen-Yu Tsai) Date: Mon, 23 Nov 2020 12:47:32 +0800 Subject: [PATCH v3 6/6] ARM: dts: sun8i: v3s: Add video engine node In-Reply-To: <20201116125617.7597-7-m.cerveny@computer.org> References: <20201116125617.7597-1-m.cerveny@computer.org> <20201116125617.7597-7-m.cerveny@computer.org> Message-ID: On Mon, Nov 16, 2020 at 8:58 PM Martin Cerveny wrote: > > Allwinner V3S SoC has a video engine. > Add a node for it. > > Signed-off-by: Martin Cerveny Acked-by: Chen-Yu Tsai From sergio.paracuellos at gmail.com Mon Nov 23 09:36:30 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:30 +0100 Subject: [PATCH 0/7] staging: mt7621-pci: update to last kernel APIs and other related minor cleanups Message-ID: <20201123093637.8300-1-sergio.paracuellos@gmail.com> This patch series updates the driver to use last kernel apis and other minor cleanup changes related with this changes. LOC decressed a bit which is always a good thing :) This serias has been tested in GnuBee PC1 boards resulting in a working platform. Best regards, Sergio Paracuellos Sergio Paracuellos (7): staging: mt7621-pci: remove bus ranges related code staging: mt7621-pci: remove 'offset' with mem and io resource sizes staging: mt7621-pci: add comment to clarify IO resource in this driver staging: mt7621-pci: review 'pci_host_bridge' assigned variables staging: mt7621-pci: parse and prepare resources in 'mt7621_pci_parse_request_of_pci_ranges' staging: mt7621-pci: convert to use 'devm_platform_ioremap_resource' staging: mt7621-pci: remove 'RALINK_PCI_IMBASEBAR0_ADDR' register drivers/staging/mt7621-pci/pci-mt7621.c | 97 ++++++++----------------- 1 file changed, 30 insertions(+), 67 deletions(-) -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:31 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:31 +0100 Subject: [PATCH 1/7] staging: mt7621-pci: remove bus ranges related code In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-2-sergio.paracuellos@gmail.com> Bus ranges are now discovered by default. Hence remove its related code from the driver. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 7b38ef9f8560..3e8dddf5ec79 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -117,7 +117,6 @@ struct mt7621_pcie_port { * @base: IO Mapped Register Base * @io: IO resource * @mem: non-prefetchable memory resource - * @busn: bus range * @offset: IO / Memory offset * @dev: Pointer to PCIe device * @io_map_base: virtual memory base address for io @@ -131,7 +130,6 @@ struct mt7621_pcie { struct device *dev; struct resource io; struct resource mem; - struct resource busn; struct { resource_size_t mem; resource_size_t io; @@ -299,7 +297,6 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) struct device_node *node = dev->of_node; struct of_pci_range_parser parser; struct of_pci_range range; - int err; if (of_pci_range_parser_init(&parser, node)) { dev_err(dev, "missing \"ranges\" property\n"); @@ -324,15 +321,6 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) } } - err = of_pci_parse_bus_range(node, &pcie->busn); - if (err < 0) { - dev_err(dev, "failed to parse bus ranges property: %d\n", err); - pcie->busn.name = node->name; - pcie->busn.start = 0; - pcie->busn.end = 0xff; - pcie->busn.flags = IORESOURCE_BUS; - } - set_io_port_base(pcie->io_map_base); return 0; @@ -666,7 +654,6 @@ static int mt7621_pcie_register_host(struct pci_host_bridge *host, struct mt7621_pcie *pcie = pci_host_bridge_priv(host); list_splice_init(res, &host->windows); - host->busnr = pcie->busn.start; host->dev.parent = pcie->dev; host->ops = &mt7621_pci_ops; host->map_irq = mt7621_map_irq; -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:32 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:32 +0100 Subject: [PATCH 2/7] staging: mt7621-pci: remove 'offset' with mem and io resource sizes In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-3-sergio.paracuellos@gmail.com> Offset contains resources size for both io and memory resources. Those fields are directly initialized to zero and set up using 'pci_add_resource_offset' function. Instead of doing that remove them and use directly function 'pci_add_resource' where zero is passed directly to its internal call to 'pci_add_resource_offset'. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 3e8dddf5ec79..219b35937285 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -117,7 +117,6 @@ struct mt7621_pcie_port { * @base: IO Mapped Register Base * @io: IO resource * @mem: non-prefetchable memory resource - * @offset: IO / Memory offset * @dev: Pointer to PCIe device * @io_map_base: virtual memory base address for io * @ports: pointer to PCIe port information @@ -130,10 +129,6 @@ struct mt7621_pcie { struct device *dev; struct resource io; struct resource mem; - struct { - resource_size_t mem; - resource_size_t io; - } offset; unsigned long io_map_base; struct list_head ports; int irq_map[PCIE_P2P_CNT]; @@ -312,11 +307,9 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) of_pci_range_to_resource(&range, node, &pcie->io); pcie->io.start = range.cpu_addr; pcie->io.end = range.cpu_addr + range.size - 1; - pcie->offset.io = 0x00000000UL; break; case IORESOURCE_MEM: of_pci_range_to_resource(&range, node, &pcie->mem); - pcie->offset.mem = 0x00000000UL; break; } } @@ -644,8 +637,8 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie) static void mt7621_pcie_add_resources(struct mt7621_pcie *pcie, struct list_head *res) { - pci_add_resource_offset(res, &pcie->io, pcie->offset.io); - pci_add_resource_offset(res, &pcie->mem, pcie->offset.mem); + pci_add_resource(res, &pcie->io); + pci_add_resource(res, &pcie->mem); } static int mt7621_pcie_register_host(struct pci_host_bridge *host, -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:33 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:33 +0100 Subject: [PATCH 3/7] staging: mt7621-pci: add comment to clarify IO resource in this driver In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-4-sergio.paracuellos@gmail.com> Because IO_SPACE_LIMIT for mips is 0xFFFF but this platform uses P?I IO resource at 0x001e160000. Hence instead of directly use some more accurate functions from the PCI kernel for this driver some things must be done in a different way to make things work. Add this explanation as a comment where the IO resource is parsed and virtually mapped into memory. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 219b35937285..1f9e75db5298 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -298,6 +298,13 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) return -EINVAL; } + /* + * IO_SPACE_LIMIT for MIPS is 0xffff but this platform uses IO at + * upper address 0x001e160000 so we have to get the resource from + * the DT because when it has been requested it failed and has been + * removed from bridge->dma_ranges and bridge->windows. So parse it + * and remap it manually to make things work. + */ for_each_of_pci_range(&parser, &range) { switch (range.flags & IORESOURCE_TYPE_BITS) { case IORESOURCE_IO: -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:34 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:34 +0100 Subject: [PATCH 4/7] staging: mt7621-pci: review 'pci_host_bridge' assigned variables In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-5-sergio.paracuellos@gmail.com> PCI kernel apis now set some variables related with pci_host_bridge by default and it is not necessary to setup them in driver code. Host bridge parent device is set by default to the platform device and 'swizzle_irq' is also set to its default function. These two are not necessary to be set here. Hence remove them. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 1f9e75db5298..98569d9b70f2 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -654,10 +654,8 @@ static int mt7621_pcie_register_host(struct pci_host_bridge *host, struct mt7621_pcie *pcie = pci_host_bridge_priv(host); list_splice_init(res, &host->windows); - host->dev.parent = pcie->dev; host->ops = &mt7621_pci_ops; host->map_irq = mt7621_map_irq; - host->swizzle_irq = pci_common_swizzle; host->sysdata = pcie; return pci_host_probe(host); -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:35 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:35 +0100 Subject: [PATCH 5/7] staging: mt7621-pci: parse and prepare resources in 'mt7621_pci_parse_request_of_pci_ranges' In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-6-sergio.paracuellos@gmail.com> Remove 'mt7621_pcie_add_resources' where resources are added to the host windows moving this code into the function where all the parsing and preparing code is being done: 'mt7621_pci_parse_request_of_pci_ranges'. The memory resource has been properly parsed for the PCI APIs so we only need to retrieve it and use it in those places we need. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 44 ++++++++++++------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 98569d9b70f2..a0b3ec51c7d9 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -116,7 +116,7 @@ struct mt7621_pcie_port { * struct mt7621_pcie - PCIe host information * @base: IO Mapped Register Base * @io: IO resource - * @mem: non-prefetchable memory resource + * @mem: pointer to non-prefetchable memory resource * @dev: Pointer to PCIe device * @io_map_base: virtual memory base address for io * @ports: pointer to PCIe port information @@ -128,7 +128,7 @@ struct mt7621_pcie { void __iomem *base; struct device *dev; struct resource io; - struct resource mem; + struct resource *mem; unsigned long io_map_base; struct list_head ports; int irq_map[PCIE_P2P_CNT]; @@ -256,7 +256,7 @@ static inline void mt7621_control_deassert(struct mt7621_pcie_port *port) static void setup_cm_memory_region(struct mt7621_pcie *pcie) { - struct resource *mem_resource = &pcie->mem; + struct resource *mem_resource = pcie->mem; struct device *dev = pcie->dev; resource_size_t mask; @@ -286,12 +286,15 @@ static int mt7621_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) return irq; } -static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) +static int mt7621_pci_parse_request_of_pci_ranges(struct pci_host_bridge *host) { + struct mt7621_pcie *pcie = pci_host_bridge_priv(host); struct device *dev = pcie->dev; struct device_node *node = dev->of_node; struct of_pci_range_parser parser; + struct resource_entry *entry; struct of_pci_range range; + LIST_HEAD(res); if (of_pci_range_parser_init(&parser, node)) { dev_err(dev, "missing \"ranges\" property\n"); @@ -314,14 +317,21 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct mt7621_pcie *pcie) of_pci_range_to_resource(&range, node, &pcie->io); pcie->io.start = range.cpu_addr; pcie->io.end = range.cpu_addr + range.size - 1; - break; - case IORESOURCE_MEM: - of_pci_range_to_resource(&range, node, &pcie->mem); + set_io_port_base(pcie->io_map_base); break; } } - set_io_port_base(pcie->io_map_base); + entry = resource_list_first_type(&host->windows, IORESOURCE_MEM); + if (!entry) { + dev_err(dev, "Cannot get memory resource"); + return -EINVAL; + } + + pcie->mem = entry->res; + pci_add_resource(&res, &pcie->io); + pci_add_resource(&res, entry->res); + list_splice_init(&res, &host->windows); return 0; } @@ -641,19 +651,10 @@ static int mt7621_pcie_init_virtual_bridges(struct mt7621_pcie *pcie) return 0; } -static void mt7621_pcie_add_resources(struct mt7621_pcie *pcie, - struct list_head *res) -{ - pci_add_resource(res, &pcie->io); - pci_add_resource(res, &pcie->mem); -} - -static int mt7621_pcie_register_host(struct pci_host_bridge *host, - struct list_head *res) +static int mt7621_pcie_register_host(struct pci_host_bridge *host) { struct mt7621_pcie *pcie = pci_host_bridge_priv(host); - list_splice_init(res, &host->windows); host->ops = &mt7621_pci_ops; host->map_irq = mt7621_map_irq; host->sysdata = pcie; @@ -672,7 +673,6 @@ static int mt7621_pci_probe(struct platform_device *pdev) struct mt7621_pcie *pcie; struct pci_host_bridge *bridge; int err; - LIST_HEAD(res); if (!dev->of_node) return -ENODEV; @@ -696,7 +696,7 @@ static int mt7621_pci_probe(struct platform_device *pdev) return err; } - err = mt7621_pci_parse_request_of_pci_ranges(pcie); + err = mt7621_pci_parse_request_of_pci_ranges(bridge); if (err) { dev_err(dev, "Error requesting pci resources from ranges"); return err; @@ -718,9 +718,7 @@ static int mt7621_pci_probe(struct platform_device *pdev) setup_cm_memory_region(pcie); - mt7621_pcie_add_resources(pcie, &res); - - err = mt7621_pcie_register_host(bridge, &res); + err = mt7621_pcie_register_host(bridge); if (err) { dev_err(dev, "Error registering host\n"); return err; -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:37 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:37 +0100 Subject: [PATCH 7/7] staging: mt7621-pci: remove 'RALINK_PCI_IMBASEBAR0_ADDR' register In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-8-sergio.paracuellos@gmail.com> Register 'RALINK_PCI_IMBASEBAR0_ADDR' contains internal memory base address for BAR0. We don't really need to write anything there at all since its initial value contains always a desired valid value. Hence remove register definition and related code. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index 4cdaccbcc97c..c3532bc138fb 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -68,7 +68,6 @@ #define MT7621_NEXT_PORT 0x1000 #define RALINK_PCI_BAR0SETUP_ADDR 0x0010 -#define RALINK_PCI_IMBASEBAR0_ADDR 0x0018 #define RALINK_PCI_ID 0x0030 #define RALINK_PCI_CLASS 0x0034 #define RALINK_PCI_SUBID 0x0038 @@ -83,7 +82,6 @@ #define PCIE_PORT_CLK_EN(x) BIT(24 + (x)) #define PCIE_PORT_LINKUP BIT(0) -#define MEMORY_BASE 0x0 #define PERST_MODE_MASK GENMASK(11, 10) #define PERST_MODE_GPIO BIT(10) #define PERST_DELAY_MS 100 @@ -543,8 +541,6 @@ static void mt7621_pcie_enable_port(struct mt7621_pcie_port *port) /* map 2G DDR region */ pcie_write(pcie, PCIE_BAR_MAP_MAX | PCIE_BAR_ENABLE, offset + RALINK_PCI_BAR0SETUP_ADDR); - pcie_write(pcie, MEMORY_BASE, - offset + RALINK_PCI_IMBASEBAR0_ADDR); /* configure class code and revision ID */ pcie_write(pcie, PCIE_CLASS_CODE | PCIE_REVISION_ID, -- 2.25.1 From sergio.paracuellos at gmail.com Mon Nov 23 09:36:36 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 23 Nov 2020 10:36:36 +0100 Subject: [PATCH 6/7] staging: mt7621-pci: convert to use 'devm_platform_ioremap_resource' In-Reply-To: <20201123093637.8300-1-sergio.paracuellos@gmail.com> References: <20201123093637.8300-1-sergio.paracuellos@gmail.com> Message-ID: <20201123093637.8300-7-sergio.paracuellos@gmail.com> Instead of getting resources parsing from DT first and remaping afterwards, this can be done in one step using the kernel function 'devm_platform_ioremap_resource'. Hence, update to use it. Signed-off-by: Sergio Paracuellos --- drivers/staging/mt7621-pci/pci-mt7621.c | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/staging/mt7621-pci/pci-mt7621.c b/drivers/staging/mt7621-pci/pci-mt7621.c index a0b3ec51c7d9..4cdaccbcc97c 100644 --- a/drivers/staging/mt7621-pci/pci-mt7621.c +++ b/drivers/staging/mt7621-pci/pci-mt7621.c @@ -337,28 +337,18 @@ static int mt7621_pci_parse_request_of_pci_ranges(struct pci_host_bridge *host) } static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, - struct device_node *node, int slot) { struct mt7621_pcie_port *port; struct device *dev = pcie->dev; struct platform_device *pdev = to_platform_device(dev); - struct device_node *pnode = dev->of_node; - struct resource regs; char name[10]; - int err; port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); if (!port) return -ENOMEM; - err = of_address_to_resource(pnode, slot + 1, ®s); - if (err) { - dev_err(dev, "missing \"reg\" property\n"); - return err; - } - - port->base = devm_ioremap_resource(dev, ®s); + port->base = devm_platform_ioremap_resource(pdev, slot + 1); if (IS_ERR(port->base)) return PTR_ERR(port->base); @@ -399,17 +389,11 @@ static int mt7621_pcie_parse_port(struct mt7621_pcie *pcie, static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie) { struct device *dev = pcie->dev; + struct platform_device *pdev = to_platform_device(dev); struct device_node *node = dev->of_node, *child; - struct resource regs; int err; - err = of_address_to_resource(node, 0, ®s); - if (err) { - dev_err(dev, "missing \"reg\" property\n"); - return err; - } - - pcie->base = devm_ioremap_resource(dev, ®s); + pcie->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pcie->base)) return PTR_ERR(pcie->base); @@ -425,7 +409,7 @@ static int mt7621_pcie_parse_dt(struct mt7621_pcie *pcie) slot = PCI_SLOT(err); - err = mt7621_pcie_parse_port(pcie, child, slot); + err = mt7621_pcie_parse_port(pcie, slot); if (err) { of_node_put(child); return err; -- 2.25.1 From digetx at gmail.com Mon Nov 23 11:09:20 2020 From: digetx at gmail.com (Dmitry Osipenko) Date: Mon, 23 Nov 2020 14:09:20 +0300 Subject: [PATCH v5 2/4] staging: media: Introduce NVIDIA Tegra video decoder driver In-Reply-To: References: <3d565db80f8dccafd14224924305243b37b75a07.1513038011.git.digetx@gmail.com> <5665b221-04d7-6be9-2377-8006b9563d4b@gmail.com> Message-ID: <8372dd41-64b9-64e1-960d-7b20717d5c1e@gmail.com> 23.11.2020 06:07, Ezequiel Garcia ?????: > On Sat, 21 Nov 2020 at 23:01, Dmitry Osipenko wrote: >> >> 22.11.2020 04:02, Ezequiel Garcia ?????: >>> Hi Dmitry, >>> >> ... >>>> +++ b/drivers/staging/media/tegra-vde/TODO >>>> @@ -0,0 +1,4 @@ >>>> +TODO: >>>> + - Implement V4L2 API once it gains support for stateless decoders. >>>> + >>>> +Contact: Dmitry Osipenko >>> >>> The API for H264 stateless decoding is ready. >>> See https://lkml.org/lkml/2020/11/18/795. >> >> Hello Ezequiel, >> >> Thank you for the notification! My last attempt at implementing V4L API >> support was about a year ago and it stopped once I realized that there >> is no userspace which uses that API. FFMPEG and chromium browser had >> some kind of V4L support, but it all was oriented at downstream driver >> stacks, and thus, not usable. Do you know what is the current status? >> > > The bulk of the API, which relies on the stateless decoder interface [1], > and H264 stateless V4L2 controls has been ready for some time now, > and there are various implementations supporting it. > > Chromium supports it [2], and I've tested it on chromebooks, > through chromeos builds. We haven't tried a non-chromeos build, > and I would say it's quite some work. > > GStreamer support is available as well. See [3] which should > work for the latest H264 controls (the ones being moved out of staging). > > LibreELEC developers maintain an Ffmpeg branch [4], I expect it will > be updated for the latest H264 controls soon, and hopefully merged > in mainline Ffmpeg. > > GStreamer and Ffmpeg are relatively straightforward to build and test. > > Thanks, > Ezequiel > > [1] https://www.kernel.org/doc/html/latest/userspace-api/media/v4l/dev-stateless-decoder.html > [2] https://github.com/chromium/chromium/tree/master/media/gpu/v4l2 > [3] https://gitlab.freedesktop.org/ezequielgarcia/gst-plugins-bad/-/tree/h264_stable_uapi > [4] https://github.com/Kwiboo/FFmpeg/tree/v4l2-request-hwaccel-4.3. Alright, thank you. From miguel.ojeda.sandonis at gmail.com Mon Nov 23 14:19:55 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Mon, 23 Nov 2020 15:19:55 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> Message-ID: On Sun, Nov 22, 2020 at 11:36 PM James Bottomley wrote: > > Well, it seems to be three years of someone's time plus the maintainer > review time and series disruption of nearly a thousand patches. Let's > be conservative and assume the producer worked about 30% on the series > and it takes about 5-10 minutes per patch to review, merge and for > others to rework existing series. So let's say it's cost a person year > of a relatively junior engineer producing the patches and say 100h of > review and application time. The latter is likely the big ticket item > because it's what we have in least supply in the kernel (even though > it's 20x vs the producer time). How are you arriving at such numbers? It is a total of ~200 trivial lines. > It's not about the risk of the changes it's about the cost of > implementing them. Even if you discount the producer time (which > someone gets to pay for, and if I were the engineering manager, I'd be > unhappy about), the review/merge/rework time is pretty significant in > exchange for six minor bug fixes. Fine, when a new compiler warning > comes along it's certainly reasonable to see if we can benefit from it > and the fact that the compiler people think it's worthwhile is enough > evidence to assume this initially. But at some point you have to ask > whether that assumption is supported by the evidence we've accumulated > over the time we've been using it. And if the evidence doesn't support > it perhaps it is time to stop the experiment. Maintainers routinely review 1-line trivial patches, not to mention internal API changes, etc. If some company does not want to pay for that, that's fine, but they don't get to be maintainers and claim `Supported`. Cheers, Miguel From James.Bottomley at HansenPartnership.com Mon Nov 23 15:58:06 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Mon, 23 Nov 2020 07:58:06 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> Message-ID: On Mon, 2020-11-23 at 15:19 +0100, Miguel Ojeda wrote: > On Sun, Nov 22, 2020 at 11:36 PM James Bottomley > wrote: > > Well, it seems to be three years of someone's time plus the > > maintainer review time and series disruption of nearly a thousand > > patches. Let's be conservative and assume the producer worked > > about 30% on the series and it takes about 5-10 minutes per patch > > to review, merge and for others to rework existing series. So > > let's say it's cost a person year of a relatively junior engineer > > producing the patches and say 100h of review and application > > time. The latter is likely the big ticket item because it's what > > we have in least supply in the kernel (even though it's 20x vs the > > producer time). > > How are you arriving at such numbers? It is a total of ~200 trivial > lines. Well, I used git. It says that as of today in Linus' tree we have 889 patches related to fall throughs and the first series went in in october 2017 ... ignoring a couple of outliers back to February. > > It's not about the risk of the changes it's about the cost of > > implementing them. Even if you discount the producer time (which > > someone gets to pay for, and if I were the engineering manager, I'd > > be unhappy about), the review/merge/rework time is pretty > > significant in exchange for six minor bug fixes. Fine, when a new > > compiler warning comes along it's certainly reasonable to see if we > > can benefit from it and the fact that the compiler people think > > it's worthwhile is enough evidence to assume this initially. But > > at some point you have to ask whether that assumption is supported > > by the evidence we've accumulated over the time we've been using > > it. And if the evidence doesn't support it perhaps it is time to > > stop the experiment. > > Maintainers routinely review 1-line trivial patches, not to mention > internal API changes, etc. We're also complaining about the inability to recruit maintainers: https://www.theregister.com/2020/06/30/hard_to_find_linux_maintainers_says_torvalds/ And burn out: http://antirez.com/news/129 The whole crux of your argument seems to be maintainers' time isn't important so we should accept all trivial patches ... I'm pushing back on that assumption in two places, firstly the valulessness of the time and secondly that all trivial patches are valuable. > If some company does not want to pay for that, that's fine, but they > don't get to be maintainers and claim `Supported`. What I'm actually trying to articulate is a way of measuring value of the patch vs cost ... it has nothing really to do with who foots the actual bill. One thesis I'm actually starting to formulate is that this continual devaluing of maintainers is why we have so much difficulty keeping and recruiting them. James From joe at perches.com Mon Nov 23 16:32:41 2020 From: joe at perches.com (Joe Perches) Date: Mon, 23 Nov 2020 08:32:41 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> Message-ID: <32dc7423124b51da4e144e931bf099a368ab50a8.camel@perches.com> On Mon, 2020-11-23 at 07:58 -0800, James Bottomley wrote: > We're also complaining about the inability to recruit maintainers: > > https://www.theregister.com/2020/06/30/hard_to_find_linux_maintainers_says_torvalds/ > > And burn out: > > http://antirez.com/news/129 https://www.wired.com/story/open-source-coders-few-tired/ > What I'm actually trying to articulate is a way of measuring value of > the patch vs cost ... it has nothing really to do with who foots the > actual bill. It's unclear how to measure value in consistency. But one way that costs can be reduced is by automation and _not_ involving maintainers when the patch itself is provably correct. > One thesis I'm actually starting to formulate is that this continual > devaluing of maintainers is why we have so much difficulty keeping and > recruiting them. The linux kernel has something like 1500 different maintainers listed in the MAINTAINERS file. That's not a trivial number. $ git grep '^M:' MAINTAINERS | sort | uniq -c | wc -l 1543 $ git grep '^M:' MAINTAINERS| cut -f1 -d'<' | sort | uniq -c | wc -l 1446 I think the question you are asking is about trust and how it effects development. And back to that wired story, the actual number of what you might be considering to be maintainers is likely less than 10% of the listed numbers above. From nsaenzjulienne at suse.de Mon Nov 23 17:19:35 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 18:19:35 +0100 Subject: [PATCH v4 01/11] firmware: raspberrypi: Keep count of all consumers In-Reply-To: <20201113072615.GE356503@dtor-ws> References: <20201112163630.17177-1-nsaenzjulienne@suse.de> <20201112163630.17177-2-nsaenzjulienne@suse.de> <20201113072615.GE356503@dtor-ws> Message-ID: On Thu, 2020-11-12 at 23:26 -0800, Dmitry Torokhov wrote: > On Thu, Nov 12, 2020 at 07:52:14PM +0200, Andy Shevchenko wrote: > > On Thu, Nov 12, 2020 at 6:40 PM Nicolas Saenz Julienne > > wrote: > > > > > > When unbinding the firmware device we need to make sure it has no > > > consumers left. Otherwise we'd leave them with a firmware handle > > > pointing at freed memory. > > > > > > Keep a reference count of all consumers and introduce rpi_firmware_put() > > > which will permit automatically decrease the reference count upon > > > unbinding consumer drivers. > > > > ... > > > > > ?/** > > > - * rpi_firmware_get - Get pointer to rpi_firmware structure. > > > ??* @firmware_node: Pointer to the firmware Device Tree node. > > > ??* > > > + * The reference to rpi_firmware has to be released with rpi_firmware_put(). > > > + * > > > ??* Returns NULL is the firmware device is not ready. > > > ??*/ > > > ?struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) > > > ?{ > > > ????????struct platform_device *pdev = of_find_device_by_node(firmware_node); > > > + struct rpi_firmware *fw; > > > > > > ????????if (!pdev) > > > ????????????????return NULL; > > > > > > - return platform_get_drvdata(pdev); > > > + fw = platform_get_drvdata(pdev); > > > + if (!fw) > > > + return NULL; > > > + > > > + if (!kref_get_unless_zero(&fw->consumers)) > > > + return NULL; > > Hi Andy, Dimitry, > > Don't we have a more traditional way of doing this, i.e. > > try_module_get() coupled with get_device() ? > > get_device() will make sure that device is there, but gives no > assurances that device is bound to a driver, so it will not help with > the racy access to firmware via platform_get_drvdata() call. I also looked at using get/put_device() just as a means for refcounting (i.e. replacing fw->consumers), but I can't make it work either. I'd need a way to hook up into one of the struct device_ktype release() functions. AFAIK it's not possible for private uses like this. IIUC the way to do this would be to bypass platform device and create a special device class/bus for RPi's firmware dependent devices (I could pretty much copy SCMI's implementation), but I fear that's overkill. So, for now I'll stick with the kref based implementation, I'll be happy to change it if you find a better solution. :) Regards, Nicolas -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 488 bytes Desc: This is a digitally signed message part URL: From nsaenzjulienne at suse.de Mon Nov 23 18:38:21 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:21 +0100 Subject: [PATCH v5 00/11] Raspberry Pi PoE HAT fan support Message-ID: <20201123183833.18750-1-nsaenzjulienne@suse.de> The aim of this series is to add support to the fan found on RPi's PoE HAT. Some commentary on the design can be found below. But the imporant part to the people CC'd here not involved with PWM is that, in order to achieve this properly, we also have to fix the firmware interface the driver uses to communicate with the PWM bus (and many other low level functions). Specifically, we have to make sure the firmware interface isn't unbound while consumers are still up. So, patch #1 & #2 introduce reference counting in the firwmware interface driver and patches #3 to #8 update all firmware users. Patches #9 to #11 introduce the new PWM driver. I sent everything as a single series as the final version of the PWM drivers depends on the firwmare fixes, but I'll be happy to split this into two separate series if you think it's better. --- Original cover letter below --- This series aims at adding support to RPi's official PoE HAT fan[1]. The HW setup is the following: | Raspberry Pi | PoE HAT | arm core -> Mailbox -> RPi co-processor -> I2C -> Atmel MCU -> PWM -> FAN The arm cores have only access to the mailbox interface, as i2c0, even if physically accessible, is to be used solely by the co-processor (VideoCore 4/6). This series implements a PWM bus, and has pwm-fan sitting on top of it as per this discussion: https://lkml.org/lkml/2018/9/2/486. Although this design has a series of shortcomings: - It depends on a DT binding: it's not flexible if a new hat shows up with new functionality, we're not 100% sure we'll be able to expand it without breaking backwards compatibility. But without it we can't make use of DT thermal-zones, which IMO is overkill. - We're using pwm-fan, writing a hwmon driver would, again, give us more flexibility, but it's not really needed at the moment. I personally think that it's not worth the effort, it's unlikely we'll get things right in advance. And ultimately, if the RPi people come up with something new, we can always write a new driver/bindings from scratch (as in not reusing previous code). That said, I'm more than happy to change things if there is a consensus that another design will do the trick. [1] https://www.raspberrypi.org/blog/introducing-power-over-ethernet-poe-hat/ --- Changes since v4: - Cleanup devm calls - Rename compatible string so it's unique to the PoE HAT Changes since v3: - Split first patch, #1 introduces refcount, then #2 the devm function - Fix touchscreen function - Use kref Changes since v2: - Introduce devm_rpi_firmware_get() - Small cleanups in PWM driver Changes since v1: - Address PWM driver changes - Fix binding, now with 2 cells Nicolas Saenz Julienne (11): firmware: raspberrypi: Keep count of all consumers firmware: raspberrypi: Introduce devm_rpi_firmware_get() clk: bcm: rpi: Release firmware handle on unbind gpio: raspberrypi-exp: Release firmware handle on unbind reset: raspberrypi: Release firmware handle on unbind soc: bcm: raspberrypi-power: Release firmware handle on unbind staging: vchiq: Release firmware handle on unbind input: raspberrypi-ts: Release firmware handle when not needed dt-bindings: pwm: Add binding for RPi firmware PWM bus DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support pwm: Add Raspberry Pi Firmware based PWM bus .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 ++ arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++ drivers/clk/bcm/clk-raspberrypi.c | 2 +- drivers/firmware/raspberrypi.c | 66 +++++- drivers/gpio/gpio-raspberrypi-exp.c | 2 +- drivers/input/touchscreen/raspberrypi-ts.c | 2 +- drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++ drivers/reset/reset-raspberrypi.c | 2 +- drivers/soc/bcm/raspberrypi-power.c | 2 +- .../interface/vchiq_arm/vchiq_arm.c | 2 +- .../pwm/raspberrypi,firmware-poe-pwm.h | 13 ++ include/soc/bcm2835/raspberrypi-firmware.h | 10 + 14 files changed, 391 insertions(+), 10 deletions(-) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:22 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:22 +0100 Subject: [PATCH v5 01/11] firmware: raspberrypi: Keep count of all consumers In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-2-nsaenzjulienne@suse.de> When unbinding the firmware device we need to make sure it has no consumers left. Otherwise we'd leave them with a firmware handle pointing at freed memory. Keep a reference count of all consumers and introduce rpi_firmware_put() which will permit automatically decrease the reference count upon unbinding consumer drivers. Suggested-by: Uwe Kleine-K?nig Signed-off-by: Nicolas Saenz Julienne --- Changes since v3: - Use kref instead of waiting on refcount drivers/firmware/raspberrypi.c | 37 +++++++++++++++++++--- include/soc/bcm2835/raspberrypi-firmware.h | 2 ++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 30259dc9b805..ed793aef7851 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -27,6 +28,8 @@ struct rpi_firmware { struct mbox_chan *chan; /* The property channel. */ struct completion c; u32 enabled; + + struct kref consumers; }; static DEFINE_MUTEX(transaction_lock); @@ -225,12 +228,27 @@ static void rpi_register_clk_driver(struct device *dev) -1, NULL, 0); } +static void rpi_firmware_delete(struct kref *kref) +{ + struct rpi_firmware *fw = container_of(kref, struct rpi_firmware, + consumers); + + mbox_free_channel(fw->chan); + kfree(fw); +} + +void rpi_firmware_put(struct rpi_firmware *fw) +{ + kref_put(&fw->consumers, rpi_firmware_delete); +} +EXPORT_SYMBOL_GPL(rpi_firmware_put); + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct rpi_firmware *fw; - fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL); + fw = kzalloc(sizeof(*fw), GFP_KERNEL); if (!fw) return -ENOMEM; @@ -247,6 +265,7 @@ static int rpi_firmware_probe(struct platform_device *pdev) } init_completion(&fw->c); + kref_init(&fw->consumers); platform_set_drvdata(pdev, fw); @@ -275,25 +294,35 @@ static int rpi_firmware_remove(struct platform_device *pdev) rpi_hwmon = NULL; platform_device_unregister(rpi_clk); rpi_clk = NULL; - mbox_free_channel(fw->chan); + + rpi_firmware_put(fw); return 0; } /** - * rpi_firmware_get - Get pointer to rpi_firmware structure. * @firmware_node: Pointer to the firmware Device Tree node. * + * The reference to rpi_firmware has to be released with rpi_firmware_put(). + * * Returns NULL is the firmware device is not ready. */ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { struct platform_device *pdev = of_find_device_by_node(firmware_node); + struct rpi_firmware *fw; if (!pdev) return NULL; - return platform_get_drvdata(pdev); + fw = platform_get_drvdata(pdev); + if (!fw) + return NULL; + + if (!kref_get_unless_zero(&fw->consumers)) + return NULL; + + return fw; } EXPORT_SYMBOL_GPL(rpi_firmware_get); diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index cc9cdbc66403..fdfef7fe40df 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -140,6 +140,7 @@ int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len); int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); +void rpi_firmware_put(struct rpi_firmware *fw); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, @@ -154,6 +155,7 @@ static inline int rpi_firmware_property_list(struct rpi_firmware *fw, return -ENOSYS; } +static inline void rpi_firmware_put(struct rpi_firmware *fw) { } static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) { return NULL; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:23 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:23 +0100 Subject: [PATCH v5 02/11] firmware: raspberrypi: Introduce devm_rpi_firmware_get() In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-3-nsaenzjulienne@suse.de> It'll simplify the firmware handling for most consumers. Suggested-by: Bartosz Golaszewski Signed-off-by: Nicolas Saenz Julienne --- Changes since v4: - Rearrange function calls for clarity, same functionality Changes since v2: - Create devm_rpi_firmware_get() drivers/firmware/raspberrypi.c | 29 ++++++++++++++++++++++ include/soc/bcm2835/raspberrypi-firmware.h | 8 ++++++ 2 files changed, 37 insertions(+) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index ed793aef7851..e2a5f6f59357 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -243,6 +243,13 @@ void rpi_firmware_put(struct rpi_firmware *fw) } EXPORT_SYMBOL_GPL(rpi_firmware_put); +static void devm_rpi_firmware_put(void *data) +{ + struct rpi_firmware *fw = data; + + rpi_firmware_put(fw); +} + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -326,6 +333,28 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) } EXPORT_SYMBOL_GPL(rpi_firmware_get); +/** + * devm_rpi_firmware_get - Get pointer to rpi_firmware structure. + * @firmware_node: Pointer to the firmware Device Tree node. + * + * Returns NULL is the firmware device is not ready. + */ +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + struct rpi_firmware *fw; + + fw = rpi_firmware_get(firmware_node); + if (!fw) + return NULL; + + if (devm_add_action_or_reset(dev, devm_rpi_firmware_put, fw)) + return NULL; + + return fw; +} +EXPORT_SYMBOL_GPL(devm_rpi_firmware_get); + static const struct of_device_id rpi_firmware_of_match[] = { { .compatible = "raspberrypi,bcm2835-firmware", }, {}, diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index fdfef7fe40df..73ad784fca96 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -142,6 +142,8 @@ int rpi_firmware_property_list(struct rpi_firmware *fw, void *data, size_t tag_size); void rpi_firmware_put(struct rpi_firmware *fw); struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node); +struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node); #else static inline int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *data, size_t len) @@ -160,6 +162,12 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware { return NULL; } + +static inline struct rpi_firmware *devm_rpi_firmware_get(struct device *dev, + struct device_node *firmware_node) +{ + return NULL; +} #endif #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:24 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:24 +0100 Subject: [PATCH v5 03/11] clk: bcm: rpi: Release firmware handle on unbind In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-4-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/clk/bcm/clk-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index f89b9cfc4309..dd3b71eafabf 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -314,7 +314,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) return -ENOENT; } - firmware = rpi_firmware_get(firmware_node); + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); of_node_put(firmware_node); if (!firmware) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:26 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:26 +0100 Subject: [PATCH v5 05/11] reset: raspberrypi: Release firmware handle on unbind In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-6-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/reset/reset-raspberrypi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/reset-raspberrypi.c b/drivers/reset/reset-raspberrypi.c index 02f59c06f69b..fa23db554bcf 100644 --- a/drivers/reset/reset-raspberrypi.c +++ b/drivers/reset/reset-raspberrypi.c @@ -82,7 +82,7 @@ static int rpi_reset_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(np); + fw = devm_rpi_firmware_get(&pdev->dev, np); of_node_put(np); if (!fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:25 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:25 +0100 Subject: [PATCH v5 04/11] gpio: raspberrypi-exp: Release firmware handle on unbind In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-5-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne Acked-by: Bartosz Golaszewski --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/gpio/gpio-raspberrypi-exp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-raspberrypi-exp.c b/drivers/gpio/gpio-raspberrypi-exp.c index bb100e0124e6..64a552ecc2ad 100644 --- a/drivers/gpio/gpio-raspberrypi-exp.c +++ b/drivers/gpio/gpio-raspberrypi-exp.c @@ -208,7 +208,7 @@ static int rpi_exp_gpio_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:28 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:28 +0100 Subject: [PATCH v5 07/11] staging: vchiq: Release firmware handle on unbind In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-8-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index f500a7043805..6c196cade4a0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -2732,7 +2732,7 @@ static int vchiq_probe(struct platform_device *pdev) return -ENOENT; } - drvdata->fw = rpi_firmware_get(fw_node); + drvdata->fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!drvdata->fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:27 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:27 +0100 Subject: [PATCH v5 06/11] soc: bcm: raspberrypi-power: Release firmware handle on unbind In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-7-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/soc/bcm/raspberrypi-power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index 5d1aacdd84ef..068715d6e66d 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -177,7 +177,7 @@ static int rpi_power_probe(struct platform_device *pdev) return -ENODEV; } - rpi_domains->fw = rpi_firmware_get(fw_np); + rpi_domains->fw = devm_rpi_firmware_get(&pdev->dev, fw_np); of_node_put(fw_np); if (!rpi_domains->fw) return -EPROBE_DEFER; -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:30 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:30 +0100 Subject: [PATCH v5 09/11] dt-bindings: pwm: Add binding for RPi firmware PWM bus In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-10-nsaenzjulienne@suse.de> The PWM bus controlling the fan in RPi's official PoE hat can only be controlled by the board's co-processor. Signed-off-by: Nicolas Saenz Julienne Reviewed-by: Rob Herring --- Changes since v4: - Rename compatible string to be more explicit with the bus' limitations Changes since v3: - Fix example Changes since v1: - Update bindings to use 2 #pwm-cells .../arm/bcm/raspberrypi,bcm2835-firmware.yaml | 20 +++++++++++++++++++ .../pwm/raspberrypi,firmware-poe-pwm.h | 13 ++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml index a2c63c8b1d10..e3664eab0f6a 100644 --- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml +++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.yaml @@ -64,6 +64,21 @@ properties: - compatible - "#reset-cells" + pwm: + type: object + + properties: + compatible: + const: raspberrypi,firmware-poe-pwm + + "#pwm-cells": + # See pwm.yaml in this directory for a description of the cells format. + const: 2 + + required: + - compatible + - "#pwm-cells" + additionalProperties: false required: @@ -87,5 +102,10 @@ examples: compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + pwm: pwm { + compatible = "raspberrypi,firmware-poe-pwm"; + #pwm-cells = <2>; + }; }; ... diff --git a/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h b/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h new file mode 100644 index 000000000000..27c5ce68847b --- /dev/null +++ b/include/dt-bindings/pwm/raspberrypi,firmware-poe-pwm.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Nicolas Saenz Julienne + * Author: Nicolas Saenz Julienne + */ + +#ifndef _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H +#define _DT_BINDINGS_RASPBERRYPI_FIRMWARE_PWM_H + +#define RASPBERRYPI_FIRMWARE_PWM_POE 0 +#define RASPBERRYPI_FIRMWARE_PWM_NUM 1 + +#endif -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:31 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:31 +0100 Subject: [PATCH v5 10/11] DO NOT MERGE: ARM: dts: Add RPi's official PoE hat support In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-11-nsaenzjulienne@suse.de> This is an example on how to enable the fan on top of RPi's official PoE hat. Signed-off-by: Nicolas Saenz Julienne --- Changes since v1: - Update patch to use 2 pwm cells arch/arm/boot/dts/bcm2711-rpi-4-b.dts | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts index 403bacf986eb..9ae44620c5b8 100644 --- a/arch/arm/boot/dts/bcm2711-rpi-4-b.dts +++ b/arch/arm/boot/dts/bcm2711-rpi-4-b.dts @@ -5,6 +5,7 @@ #include "bcm283x-rpi-usb-peripheral.dtsi" #include +#include / { compatible = "raspberrypi,4-model-b", "brcm,bcm2711"; @@ -68,6 +69,54 @@ sd_vcc_reg: sd_vcc_reg { enable-active-high; gpio = <&expgpio 6 GPIO_ACTIVE_HIGH>; }; + + fan: pwm-fan { + compatible = "pwm-fan"; + cooling-levels = <0 50 150 255>; + #cooling-cells = <2>; + pwms = <&fwpwm RASPBERRYPI_FIRMWARE_PWM_POE 80000>; + }; + + thermal-zones { + cpu_thermal: cpu-thermal { + trips { + threshold: trip-point at 0 { + temperature = <45000>; + hysteresis = <5000>; + type = "active"; + }; + + target: trip-point at 1 { + temperature = <50000>; + hysteresis = <2000>; + type = "active"; + }; + + cpu_hot: cpu_hot at 0 { + temperature = <55000>; + hysteresis = <2000>; + type = "active"; + }; + }; + + cooling-maps { + map0 { + trip = <&threshold>; + cooling-device = <&fan 0 1>; + }; + + map1 { + trip = <&target>; + cooling-device = <&fan 1 2>; + }; + + map2 { + trip = <&cpu_hot>; + cooling-device = <&fan 2 3>; + }; + }; + }; + }; }; &ddc0 { @@ -103,6 +152,11 @@ reset: reset { compatible = "raspberrypi,firmware-reset"; #reset-cells = <1>; }; + + fwpwm: pwm { + compatible = "raspberrypi,firmware-poe-pwm"; + #pwm-cells = <2>; + }; }; &gpio { -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:32 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:32 +0100 Subject: [PATCH v5 11/11] pwm: Add Raspberry Pi Firmware based PWM bus In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-12-nsaenzjulienne@suse.de> Adds support to control the PWM bus available in official Raspberry Pi PoE HAT. Only RPi's co-processor has access to it, so commands have to be sent through RPi's firmware mailbox interface. Signed-off-by: Nicolas Saenz Julienne --- Changes since v3: - Rename compatible string to be more explicit WRT to bus's limitations Changes since v2: - Use devm_rpi_firmware_get() - Rename driver - Small cleanups Changes since v1: - Use default pwm bindings and get rid of xlate() function - Correct spelling errors - Correct apply() function - Round values - Fix divisions in arm32 mode - Small cleanups drivers/pwm/Kconfig | 9 ++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-raspberrypi-poe.c | 216 ++++++++++++++++++++++++++++++ 3 files changed, 226 insertions(+) create mode 100644 drivers/pwm/pwm-raspberrypi-poe.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 0937e1c047ac..75e2344703b3 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -423,6 +423,15 @@ config PWM_PXA To compile this driver as a module, choose M here: the module will be called pwm-pxa. +config PWM_RASPBERRYPI_POE + tristate "Raspberry Pi Firwmware PoE Hat PWM support" + # Make sure not 'y' when RASPBERRYPI_FIRMWARE is 'm'. This can only + # happen when COMPILE_TEST=y, hence the added !RASPBERRYPI_FIRMWARE. + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + Enable Raspberry Pi firmware controller PWM bus used to control the + official RPI PoE hat + config PWM_RCAR tristate "Renesas R-Car PWM support" depends on ARCH_RENESAS || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 18b89d7fd092..ed28d7bd4c64 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_PWM_MXS) += pwm-mxs.o obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o obj-$(CONFIG_PWM_PXA) += pwm-pxa.o +obj-$(CONFIG_PWM_RASPBERRYPI_POE) += pwm-raspberrypi-poe.o obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o diff --git a/drivers/pwm/pwm-raspberrypi-poe.c b/drivers/pwm/pwm-raspberrypi-poe.c new file mode 100644 index 000000000000..24b498839fcc --- /dev/null +++ b/drivers/pwm/pwm-raspberrypi-poe.c @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2020 Nicolas Saenz Julienne + * For more information on Raspberry Pi's PoE hat see: + * https://www.raspberrypi.org/products/poe-hat/ + * + * Limitations: + * - No disable bit, so a disabled PWM is simulated by duty_cycle 0 + * - Only normal polarity + * - Fixed 12.5 kHz period + * + * The current period is completed when HW is reconfigured. + */ + +#include +#include +#include +#include + +#include +#include + +#define RPI_PWM_MAX_DUTY 255 +#define RPI_PWM_PERIOD_NS 80000 /* 12.5 kHz */ + +#define RPI_PWM_CUR_DUTY_REG 0x0 +#define RPI_PWM_DEF_DUTY_REG 0x1 + +struct raspberrypi_pwm { + struct rpi_firmware *firmware; + struct pwm_chip chip; + unsigned int duty_cycle; +}; + +struct raspberrypi_pwm_prop { + __le32 reg; + __le32 val; + __le32 ret; +} __packed; + +static inline struct raspberrypi_pwm *to_raspberrypi_pwm(struct pwm_chip *chip) +{ + return container_of(chip, struct raspberrypi_pwm, chip); +} + +static int raspberrypi_pwm_set_property(struct rpi_firmware *firmware, + u32 reg, u32 val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = cpu_to_le32(reg), + .val = cpu_to_le32(val), + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_SET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + return 0; +} + +static int raspberrypi_pwm_get_property(struct rpi_firmware *firmware, + u32 reg, u32 *val) +{ + struct raspberrypi_pwm_prop msg = { + .reg = reg + }; + int ret; + + ret = rpi_firmware_property(firmware, RPI_FIRMWARE_GET_POE_HAT_VAL, + &msg, sizeof(msg)); + if (ret) + return ret; + if (msg.ret) + return -EIO; + + *val = le32_to_cpu(msg.val); + + return 0; +} + +static void raspberrypi_pwm_get_state(struct pwm_chip *chip, + struct pwm_device *pwm, + struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + + state->period = RPI_PWM_PERIOD_NS; + state->duty_cycle = DIV_ROUND_CLOSEST(rpipwm->duty_cycle * RPI_PWM_PERIOD_NS, + RPI_PWM_MAX_DUTY); + state->enabled = !!(rpipwm->duty_cycle); + state->polarity = PWM_POLARITY_NORMAL; +} + +static int raspberrypi_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + const struct pwm_state *state) +{ + struct raspberrypi_pwm *rpipwm = to_raspberrypi_pwm(chip); + unsigned int duty_cycle; + int ret; + + if (state->period < RPI_PWM_PERIOD_NS || + state->polarity != PWM_POLARITY_NORMAL) + return -EINVAL; + + if (!state->enabled) + duty_cycle = 0; + else if (state->duty_cycle < RPI_PWM_PERIOD_NS) + duty_cycle = DIV_ROUND_CLOSEST_ULL(state->duty_cycle * RPI_PWM_MAX_DUTY, + RPI_PWM_PERIOD_NS); + else + duty_cycle = RPI_PWM_MAX_DUTY; + + if (duty_cycle == rpipwm->duty_cycle) + return 0; + + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set duty cycle: %d\n", ret); + return ret; + } + + /* + * This sets the default duty cycle after resetting the board, we + * updated it every time to mimic Raspberry Pi's downstream's driver + * behaviour. + */ + ret = raspberrypi_pwm_set_property(rpipwm->firmware, RPI_PWM_DEF_DUTY_REG, + duty_cycle); + if (ret) { + dev_err(chip->dev, "Failed to set default duty cycle: %d\n", ret); + return ret; + } + + rpipwm->duty_cycle = duty_cycle; + + return 0; +} + +static const struct pwm_ops raspberrypi_pwm_ops = { + .get_state = raspberrypi_pwm_get_state, + .apply = raspberrypi_pwm_apply, + .owner = THIS_MODULE, +}; + +static int raspberrypi_pwm_probe(struct platform_device *pdev) +{ + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_pwm *rpipwm; + int ret; + + firmware_node = of_get_parent(dev->of_node); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = devm_rpi_firmware_get(&pdev->dev, firmware_node); + of_node_put(firmware_node); + if (!firmware) + return -EPROBE_DEFER; + + rpipwm = devm_kzalloc(&pdev->dev, sizeof(*rpipwm), GFP_KERNEL); + if (!rpipwm) + return -ENOMEM; + + rpipwm->firmware = firmware; + rpipwm->chip.dev = dev; + rpipwm->chip.ops = &raspberrypi_pwm_ops; + rpipwm->chip.base = -1; + rpipwm->chip.npwm = RASPBERRYPI_FIRMWARE_PWM_NUM; + + platform_set_drvdata(pdev, rpipwm); + + ret = raspberrypi_pwm_get_property(rpipwm->firmware, RPI_PWM_CUR_DUTY_REG, + &rpipwm->duty_cycle); + if (ret) { + dev_err(dev, "Failed to get duty cycle: %d\n", ret); + return ret; + } + + return pwmchip_add(&rpipwm->chip); +} + +static int raspberrypi_pwm_remove(struct platform_device *pdev) +{ + struct raspberrypi_pwm *rpipwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&rpipwm->chip); +} + +static const struct of_device_id raspberrypi_pwm_of_match[] = { + { .compatible = "raspberrypi,firmware-poe-pwm", }, + { } +}; +MODULE_DEVICE_TABLE(of, raspberrypi_pwm_of_match); + +static struct platform_driver raspberrypi_pwm_driver = { + .driver = { + .name = "raspberrypi-poe-pwm", + .of_match_table = raspberrypi_pwm_of_match, + }, + .probe = raspberrypi_pwm_probe, + .remove = raspberrypi_pwm_remove, +}; +module_platform_driver(raspberrypi_pwm_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne "); +MODULE_DESCRIPTION("Raspberry Pi Firwmare Based PWM Bus Driver"); +MODULE_LICENSE("GPL v2"); -- 2.29.2 From nsaenzjulienne at suse.de Mon Nov 23 18:38:29 2020 From: nsaenzjulienne at suse.de (Nicolas Saenz Julienne) Date: Mon, 23 Nov 2020 19:38:29 +0100 Subject: [PATCH v5 08/11] input: raspberrypi-ts: Release firmware handle when not needed In-Reply-To: <20201123183833.18750-1-nsaenzjulienne@suse.de> References: <20201123183833.18750-1-nsaenzjulienne@suse.de> Message-ID: <20201123183833.18750-9-nsaenzjulienne@suse.de> Use devm_rpi_firmware_get() so as to make sure we release RPi's firmware interface when unbinding the device. Signed-off-by: Nicolas Saenz Julienne --- Changes since v3: - Release firmware handle in probe function Changes since v2: - Use devm_rpi_firmware_get(), instead of remove function drivers/input/touchscreen/raspberrypi-ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index ef6aaed217cf..5000f5fd9ec3 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -160,7 +160,7 @@ static int rpi_ts_probe(struct platform_device *pdev) touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); - + rpi_firmware_put(fw); if (error || touchbuf != 0) { dev_warn(dev, "Failed to set touchbuf, %d\n", error); return error; -- 2.29.2 From miguel.ojeda.sandonis at gmail.com Mon Nov 23 18:56:01 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Mon, 23 Nov 2020 19:56:01 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> Message-ID: On Mon, Nov 23, 2020 at 4:58 PM James Bottomley wrote: > > Well, I used git. It says that as of today in Linus' tree we have 889 > patches related to fall throughs and the first series went in in > october 2017 ... ignoring a couple of outliers back to February. I can see ~10k insertions over ~1k commits and 15 years that mention a fallthrough in the entire repo. That is including some commits (like the biggest one, 960 insertions) that have nothing to do with C fallthrough. A single kernel release has an order of magnitude more changes than this... But if we do the math, for an author, at even 1 minute per line change and assuming nothing can be automated at all, it would take 1 month of work. For maintainers, a couple of trivial lines is noise compared to many other patches. In fact, this discussion probably took more time than the time it would take to review the 200 lines. :-) > We're also complaining about the inability to recruit maintainers: > > https://www.theregister.com/2020/06/30/hard_to_find_linux_maintainers_says_torvalds/ > > And burn out: > > http://antirez.com/news/129 Accepting trivial and useful 1-line patches is not what makes a voluntary maintainer quit... Thankless work with demanding deadlines is. > The whole crux of your argument seems to be maintainers' time isn't > important so we should accept all trivial patches I have not said that, at all. In fact, I am a voluntary one and I welcome patches like this. It takes very little effort on my side to review and it helps the kernel overall. Paid maintainers are the ones that can take care of big features/reviews. > What I'm actually trying to articulate is a way of measuring value of > the patch vs cost ... it has nothing really to do with who foots the > actual bill. I understand your point, but you were the one putting it in terms of a junior FTE. In my view, 1 month-work (worst case) is very much worth removing a class of errors from a critical codebase. > One thesis I'm actually starting to formulate is that this continual > devaluing of maintainers is why we have so much difficulty keeping and > recruiting them. That may very well be true, but I don't feel anybody has devalued maintainers in this discussion. Cheers, Miguel From lkp at intel.com Mon Nov 23 19:27:48 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 24 Nov 2020 03:27:48 +0800 Subject: [staging:staging-next] BUILD SUCCESS 03c1136af504bbc2cabda76af6b27fd5f7cf8a7d Message-ID: <5fbc0d34.ubu3ZhDZJt36aXvz%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-next branch HEAD: 03c1136af504bbc2cabda76af6b27fd5f7cf8a7d Merge 5.10-rc5 into staging-testing elapsed time: 723m configs tested: 133 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig m68k hp300_defconfig arm bcm2835_defconfig sh alldefconfig m68k apollo_defconfig sh ecovec24-romimage_defconfig powerpc mpc832x_mds_defconfig xtensa virt_defconfig sh r7780mp_defconfig arm netwinder_defconfig xtensa defconfig arm u300_defconfig arm nhk8815_defconfig sh allmodconfig powerpc cm5200_defconfig arm badge4_defconfig powerpc tqm8540_defconfig microblaze mmu_defconfig arm simpad_defconfig x86_64 allyesconfig sh apsh4ad0a_defconfig xtensa iss_defconfig powerpc skiroot_defconfig powerpc makalu_defconfig powerpc icon_defconfig arm cm_x300_defconfig arm64 alldefconfig mips tb0226_defconfig powerpc iss476-smp_defconfig powerpc akebono_defconfig arm s3c6400_defconfig sparc alldefconfig mips ip32_defconfig sh se7721_defconfig powerpc ep88xc_defconfig c6x dsk6455_defconfig mips qi_lb60_defconfig arc nsimosci_hs_defconfig riscv allmodconfig mips gcw0_defconfig powerpc bluestone_defconfig mips fuloong2e_defconfig powerpc lite5200b_defconfig mips ath79_defconfig arm hackkit_defconfig mips ar7_defconfig arm realview_defconfig arm footbridge_defconfig arm mainstone_defconfig sparc64 alldefconfig arm assabet_defconfig arm colibri_pxa270_defconfig powerpc motionpro_defconfig powerpc chrp32_defconfig sh rsk7269_defconfig mips malta_qemu_32r6_defconfig arm rpc_defconfig powerpc pseries_defconfig xtensa audio_kc705_defconfig mips rbtx49xx_defconfig arm mps2_defconfig c6x evmc6474_defconfig arm spear3xx_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig i386 randconfig-a004-20201123 i386 randconfig-a003-20201123 i386 randconfig-a002-20201123 i386 randconfig-a005-20201123 i386 randconfig-a001-20201123 i386 randconfig-a006-20201123 x86_64 randconfig-a015-20201123 x86_64 randconfig-a014-20201123 x86_64 randconfig-a016-20201123 x86_64 randconfig-a011-20201123 x86_64 randconfig-a012-20201123 x86_64 randconfig-a013-20201123 i386 randconfig-a012-20201123 i386 randconfig-a013-20201123 i386 randconfig-a011-20201123 i386 randconfig-a016-20201123 i386 randconfig-a014-20201123 i386 randconfig-a015-20201123 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig x86_64 rhel x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a006-20201123 x86_64 randconfig-a003-20201123 x86_64 randconfig-a004-20201123 x86_64 randconfig-a005-20201123 x86_64 randconfig-a002-20201123 x86_64 randconfig-a001-20201123 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From lkp at intel.com Mon Nov 23 19:56:25 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 24 Nov 2020 03:56:25 +0800 Subject: [driver-core:readfile] BUILD SUCCESS 652db3de96a630e8051ffa921286000bb9ee2727 Message-ID: <5fbc13e9.VZwkanwiYuYaupKS%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core.git readfile branch HEAD: 652db3de96a630e8051ffa921286000bb9ee2727 readfile.2: new page describing readfile(2) elapsed time: 725m configs tested: 141 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig m68k hp300_defconfig arm bcm2835_defconfig sh alldefconfig m68k apollo_defconfig sh ecovec24-romimage_defconfig powerpc mpc832x_mds_defconfig xtensa virt_defconfig sh r7780mp_defconfig arm netwinder_defconfig xtensa defconfig arm u300_defconfig arm nhk8815_defconfig sh allmodconfig powerpc cm5200_defconfig arm badge4_defconfig powerpc tqm8540_defconfig microblaze mmu_defconfig arm simpad_defconfig x86_64 allyesconfig sh apsh4ad0a_defconfig xtensa iss_defconfig powerpc skiroot_defconfig powerpc makalu_defconfig powerpc icon_defconfig powerpc akebono_defconfig arm s3c6400_defconfig sparc alldefconfig mips ip32_defconfig sh se7721_defconfig powerpc ep88xc_defconfig mips bigsur_defconfig powerpc pseries_defconfig arm tegra_defconfig powerpc kmeter1_defconfig mips decstation_r4k_defconfig mips ip27_defconfig nds32 allnoconfig powerpc mvme5100_defconfig arm colibri_pxa270_defconfig m68k sun3_defconfig powerpc allnoconfig c6x dsk6455_defconfig mips qi_lb60_defconfig mips tb0226_defconfig arc nsimosci_hs_defconfig riscv allmodconfig mips gcw0_defconfig powerpc bluestone_defconfig mips fuloong2e_defconfig powerpc lite5200b_defconfig mips ath79_defconfig arm hackkit_defconfig mips ar7_defconfig arm realview_defconfig arm footbridge_defconfig arm mainstone_defconfig sparc64 alldefconfig arm assabet_defconfig powerpc motionpro_defconfig powerpc chrp32_defconfig sh rsk7269_defconfig mips malta_qemu_32r6_defconfig arm rpc_defconfig powerpc arches_defconfig powerpc currituck_defconfig arm pxa168_defconfig mips vocore2_defconfig xtensa audio_kc705_defconfig mips rbtx49xx_defconfig arm mps2_defconfig c6x evmc6474_defconfig arm spear3xx_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig i386 randconfig-a004-20201123 i386 randconfig-a003-20201123 i386 randconfig-a002-20201123 i386 randconfig-a005-20201123 i386 randconfig-a001-20201123 i386 randconfig-a006-20201123 x86_64 randconfig-a015-20201123 x86_64 randconfig-a011-20201123 x86_64 randconfig-a014-20201123 x86_64 randconfig-a016-20201123 x86_64 randconfig-a012-20201123 x86_64 randconfig-a013-20201123 i386 randconfig-a012-20201123 i386 randconfig-a013-20201123 i386 randconfig-a011-20201123 i386 randconfig-a016-20201123 i386 randconfig-a014-20201123 i386 randconfig-a015-20201123 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig x86_64 rhel x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a006-20201123 x86_64 randconfig-a003-20201123 x86_64 randconfig-a004-20201123 x86_64 randconfig-a005-20201123 x86_64 randconfig-a002-20201123 x86_64 randconfig-a001-20201123 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From jgg at nvidia.com Mon Nov 23 20:03:45 2020 From: jgg at nvidia.com (Jason Gunthorpe) Date: Mon, 23 Nov 2020 16:03:45 -0400 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: Message-ID: <20201123200345.GA38546@nvidia.com> On Fri, Nov 20, 2020 at 12:21:39PM -0600, Gustavo A. R. Silva wrote: > IB/hfi1: Fix fall-through warnings for Clang > IB/mlx4: Fix fall-through warnings for Clang > IB/qedr: Fix fall-through warnings for Clang > RDMA/mlx5: Fix fall-through warnings for Clang I picked these four to the rdma tree, thanks Jason From James.Bottomley at HansenPartnership.com Mon Nov 23 20:37:58 2020 From: James.Bottomley at HansenPartnership.com (James Bottomley) Date: Mon, 23 Nov 2020 12:37:58 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> Message-ID: <4993259d01a0064f8bb22770503490f9252f3659.camel@HansenPartnership.com> On Mon, 2020-11-23 at 19:56 +0100, Miguel Ojeda wrote: > On Mon, Nov 23, 2020 at 4:58 PM James Bottomley > wrote: > > Well, I used git. It says that as of today in Linus' tree we have > > 889 patches related to fall throughs and the first series went in > > in october 2017 ... ignoring a couple of outliers back to February. > > I can see ~10k insertions over ~1k commits and 15 years that mention > a fallthrough in the entire repo. That is including some commits > (like the biggest one, 960 insertions) that have nothing to do with C > fallthrough. A single kernel release has an order of magnitude more > changes than this... > > But if we do the math, for an author, at even 1 minute per line > change and assuming nothing can be automated at all, it would take 1 > month of work. For maintainers, a couple of trivial lines is noise > compared to many other patches. So you think a one line patch should take one minute to produce ... I really don't think that's grounded in reality. I suppose a one line patch only takes a minute to merge with b4 if no-one reviews or tests it, but that's not really desirable. > In fact, this discussion probably took more time than the time it > would take to review the 200 lines. :-) I'm framing the discussion in terms of the whole series of changes we have done for fall through, both what's in the tree currently (889 patches) both in terms of the produce and the consumer. That's what I used for my figures for cost. > > We're also complaining about the inability to recruit maintainers: > > > > https://www.theregister.com/2020/06/30/hard_to_find_linux_maintainers_says_torvalds/ > > > > And burn out: > > > > http://antirez.com/news/129 > > Accepting trivial and useful 1-line patches Part of what I'm trying to measure is the "and useful" bit because that's not a given. > is not what makes a voluntary maintainer quit... so the proverb "straw which broke the camel's back" uniquely doesn't apply to maintainers > Thankless work with demanding deadlines is. That's another potential reason, but it doesn't may other reasons less valid. > > The whole crux of your argument seems to be maintainers' time isn't > > important so we should accept all trivial patches > > I have not said that, at all. In fact, I am a voluntary one and I > welcome patches like this. It takes very little effort on my side to > review and it helps the kernel overall. Well, you know, subsystems are very different in terms of the amount of patches a maintainer has to process per release cycle of the kernel. If a maintainer is close to capacity, additional patches, however trivial, become a problem. If a maintainer has spare cycles, trivial patches may look easy. > Paid maintainers are the ones that can take care of big > features/reviews. > > > What I'm actually trying to articulate is a way of measuring value > > of the patch vs cost ... it has nothing really to do with who foots > > the actual bill. > > I understand your point, but you were the one putting it in terms of > a junior FTE. No, I evaluated the producer side in terms of an FTE. What we're mostly arguing about here is the consumer side: the maintainers and people who have to rework their patch sets. I estimated that at 100h. > In my view, 1 month-work (worst case) is very much worth > removing a class of errors from a critical codebase. > > > One thesis I'm actually starting to formulate is that this > > continual devaluing of maintainers is why we have so much > > difficulty keeping and recruiting them. > > That may very well be true, but I don't feel anybody has devalued > maintainers in this discussion. You seem to be saying that because you find it easy to merge trivial patches, everyone should. I'm reminded of a friend long ago who thought being a Tees River Pilot was a sinecure because he could navigate the Tees blindfold. What he forgot, of course, is that just because it's easy with a trawler doesn't mean it's easy with an oil tanker. In fact it takes longer to qualify as a Tees River Pilot than it does to get a PhD. James From ndesaulniers at google.com Tue Nov 24 01:32:51 2020 From: ndesaulniers at google.com (Nick Desaulniers) Date: Mon, 23 Nov 2020 17:32:51 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <202011220816.8B6591A@keescook> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> Message-ID: On Sun, Nov 22, 2020 at 8:17 AM Kees Cook wrote: > > On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > > If none of the 140 patches here fix a real bug, and there is no change > > to machine code then it sounds to me like a W=2 kind of a warning. > > FWIW, this series has found at least one bug so far: > https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ So looks like the bulk of these are: switch (x) { case 0: ++x; default: break; } I have a patch that fixes those up for clang: https://reviews.llvm.org/D91895 There's 3 other cases that don't quite match between GCC and Clang I observe in the kernel: switch (x) { case 0: ++x; default: goto y; } y:; switch (x) { case 0: ++x; default: return; } switch (x) { case 0: ++x; default: ; } Based on your link, and Nathan's comment on my patch, maybe Clang should continue to warn for the above (at least the `default: return;` case) and GCC should change? While the last case looks harmless, there were only 1 or 2 across the tree in my limited configuration testing; I really think we should just add `break`s for those. -- Thanks, ~Nick Desaulniers From kuba at kernel.org Tue Nov 24 01:46:48 2020 From: kuba at kernel.org (Jakub Kicinski) Date: Mon, 23 Nov 2020 17:46:48 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> Message-ID: <20201123174648.6a22575b@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> On Mon, 23 Nov 2020 17:32:51 -0800 Nick Desaulniers wrote: > On Sun, Nov 22, 2020 at 8:17 AM Kees Cook wrote: > > On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > > > If none of the 140 patches here fix a real bug, and there is no change > > > to machine code then it sounds to me like a W=2 kind of a warning. > > > > FWIW, this series has found at least one bug so far: > > https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ > > So looks like the bulk of these are: > switch (x) { > case 0: > ++x; > default: > break; > } > > I have a patch that fixes those up for clang: > https://reviews.llvm.org/D91895 ? From lkp at intel.com Tue Nov 24 05:05:07 2020 From: lkp at intel.com (kernel test robot) Date: Tue, 24 Nov 2020 13:05:07 +0800 Subject: [staging:staging-testing] BUILD SUCCESS 8a3f7b9665c8194f32afec9a7bb60e2376f896c6 Message-ID: <5fbc9483.u1YXQh/VUyMk7S/p%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: 8a3f7b9665c8194f32afec9a7bb60e2376f896c6 staging: rtl8723bs: remove redundant statements elapsed time: 723m configs tested: 142 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig mips bigsur_defconfig arm spear6xx_defconfig powerpc mpc8560_ads_defconfig sh sh2007_defconfig alpha defconfig riscv rv32_defconfig sh defconfig arm eseries_pxa_defconfig arm tct_hammer_defconfig arm s5pv210_defconfig arm mainstone_defconfig arm moxart_defconfig openrisc alldefconfig ia64 defconfig arm mvebu_v5_defconfig powerpc makalu_defconfig arm keystone_defconfig mips ip32_defconfig arm u300_defconfig powerpc tqm8xx_defconfig m68k mvme16x_defconfig powerpc storcenter_defconfig powerpc acadia_defconfig powerpc mpc512x_defconfig mips vocore2_defconfig m68k m5307c3_defconfig mips cu1000-neo_defconfig sh espt_defconfig mips ath79_defconfig powerpc mpc832x_mds_defconfig arm badge4_defconfig powerpc stx_gp3_defconfig arm integrator_defconfig sh ecovec24_defconfig sh rsk7203_defconfig arm gemini_defconfig sparc64 alldefconfig mips ip27_defconfig nds32 allnoconfig powerpc mvme5100_defconfig arm colibri_pxa270_defconfig m68k sun3_defconfig powerpc allnoconfig sh landisk_defconfig mips mtx1_defconfig mips nlm_xlr_defconfig xtensa common_defconfig mips maltaaprp_defconfig arm colibri_pxa300_defconfig arm lpc18xx_defconfig arm cerfcube_defconfig sh se7780_defconfig arm at91_dt_defconfig powerpc mpc8315_rdb_defconfig arm nhk8815_defconfig powerpc mpc8540_ads_defconfig sh apsh4a3a_defconfig arm magician_defconfig mips lemote2f_defconfig mips rt305x_defconfig arc axs103_smp_defconfig mips loongson1b_defconfig powerpc arches_defconfig powerpc ppc64e_defconfig arm collie_defconfig arm corgi_defconfig powerpc ppc64_defconfig powerpc taishan_defconfig mips ci20_defconfig arc nsimosci_hs_defconfig powerpc sam440ep_defconfig xtensa virt_defconfig mips tb0226_defconfig ia64 allmodconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig i386 randconfig-a004-20201123 i386 randconfig-a003-20201123 i386 randconfig-a002-20201123 i386 randconfig-a005-20201123 i386 randconfig-a001-20201123 i386 randconfig-a006-20201123 x86_64 randconfig-a015-20201123 x86_64 randconfig-a011-20201123 x86_64 randconfig-a014-20201123 x86_64 randconfig-a016-20201123 x86_64 randconfig-a012-20201123 x86_64 randconfig-a013-20201123 i386 randconfig-a012-20201123 i386 randconfig-a013-20201123 i386 randconfig-a011-20201123 i386 randconfig-a016-20201123 i386 randconfig-a014-20201123 i386 randconfig-a015-20201123 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv allmodconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a006-20201123 x86_64 randconfig-a003-20201123 x86_64 randconfig-a004-20201123 x86_64 randconfig-a005-20201123 x86_64 randconfig-a002-20201123 x86_64 randconfig-a001-20201123 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From info3 at foescof.com Tue Nov 24 12:07:50 2020 From: info3 at foescof.com (FOESCO) Date: Tue, 24 Nov 2020 13:07:50 +0100 Subject: =?Windows-1252?Q?Formaci=F3n_Bonificable_2020?= Message-ID: <5936408169640295791463@DESKTOP-MFVDD89> Buenos d?as Desde FOESCO os informamos que se encuentra abierto el plazo de inscripci?n para la presente y ?LTIMA CONVOCATORIA 2020 de Cursos Bonificables. Recordamos que los cursos van dirigidos a empleados en activo y en situaci?n de ERTE y son totalmente bonificables con cargo al Cr?dito de Formaci?n 2020. Si vuestra empresa todav?a dispone de Cr?dito de Formaci?n 2020 esta es la ?ltima oportunidad para poder consumirlo. Dese?is que os mandemos la informaci?n? Quedamos a la espera de vuestra respuesta. Saludos cordiales. Alex Pons Director FOESCO. FOESCO Formaci?n Estatal Continua. Entidad Organizadora: B200592AA www.foesco.com e-mail: cursos at foesco.net Tel: 910 323 794 (Horario de 9h a 15h y de 17h a 20h de Lunes a Viernes) FOESCO ofrece formaci?n a empresas y trabajadores en activo a trav?s de cursos bonificados por la Fundaci?n Estatal para la Formaci?n en el Empleo (antiguo FORCEM) que gestiona las acciones formativas de FORMACI?N CONTINUA para trabajadores y se rige por la ley 30/2015 de 9 de Septiembre. Antes de imprimir este e-mail piense bien si es necesario hacerlo. Before printing this e-mail please think twice if you really need it. FOESCO Tfno: 910 382 880 Email: cursos at foesco.com. La informaci?n transmitida en este mensaje est? dirigida solamente a las personas o entidades que figuran en el encabezamiento y contiene informaci?n confidencial, por lo que, si usted lo recibiera por error, por favor destr?yalo sin copiarlo, usarlo ni distribuirlo, comunic?ndolo inmediatamente al emisor del mensaje. De conformidad con lo dispuesto en el Reglamento Europeo del 2016/679, del 27 de Abril de 2016, FOESCO le informa que los datos por usted suministrados ser?n tratados con las medidas de seguridad conformes a la normativa vigente que se requiere. Dichos datos ser?n empleados con fines de gesti?n. Para el ejercicio de sus derechos de transparencia, informaci?n, acceso, rectificaci?n, supresi?n o derecho al olvido, limitaci?n del tratamiento , portabilidad de datos y oposici?n de sus datos de car?cter personal deber? dirigirse a la direcci?n del Responsable del tratamiento a C/ LAGUNA DEL MARQUESADO N?10, 28021, MADRID, "PULSANDO AQUI" y "ENVIAR" o a traves de la direcci?n de correo electr?nico: bajas at foesco.com From arnd at kernel.org Tue Nov 24 14:22:40 2020 From: arnd at kernel.org (Arnd Bergmann) Date: Tue, 24 Nov 2020 15:22:40 +0100 Subject: [PATCH v2] staging: trivial: hikey9xx: fix be32<->u32 casting warnings In-Reply-To: <20201119122737.189675-1-juant.aldea@gmail.com> References: <20201119114029.183828-1-juant.aldea@gmail.com> <20201119122737.189675-1-juant.aldea@gmail.com> Message-ID: On Thu, Nov 19, 2020 at 1:31 PM Juan Antonio Aldea-Armenteros wrote: > > This patch fixes the following warnings reported by sparse, by adding > missing __force annotations. > > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > drivers/staging/hikey9xx/hisi-spmi-controller.c:164:24: warning: cast to restricted __be32 > > drivers/staging/hikey9xx/hisi-spmi-controller.c:239:25: warning: cast from restricted __be32 > > Rationale for #164: > data is declared as u32, and it is read and then converted by means of > be32_to_cpu(). Said function expects a __be32 but data is u32, therefore > there's a type missmatch here. > > Rationale for #239: > Is the dual of #164. This time data going to be written so it > needs to be converted from cpu to __be32, but writel() expects u32 and the > output of cpu_to_be32 returns a __be32. Both of the casts look very suspicious, I'd leave these in unless someone can confirm what the actual desired behavior is. > SPMI_SLAVE_OFFSET * slave_id + > SPMI_APB_SPMI_RDATA0_BASE_ADDR + > i * SPMI_PER_DATAREG_BYTE); > - data = be32_to_cpu((__be32)data); > + data = be32_to_cpu((__be32 __force)data); > if ((bc - i * SPMI_PER_DATAREG_BYTE) >> 2) { > memcpy(buf, &data, sizeof(data)); > buf += sizeof(data); The data comes from a readl(), which contains an endian conversion on architectures that need it, such as when running the board in big-endian arm64 mode. Having a second endian-conversion on little-endian architectures means that the data is always swapped when it gets written to the register. In the original code before Mauro's commit 8788a30c12c7 ("staging: spmi: hisi-spmi-controller: use le32 macros where needed"), the data was byteswapped, and then written into the fifo register, which produced no warning but would do a double-swap on a big-endian kernel, and change the behavior from what it was before. My guess is that Mauro inadvertently fixed this driver for big-endian mode, without noticing that it was broken to start with, and that he did not actually try it with CONFIG_CPU_BIG_ENDIAN. I think the best way would be to go back to to using swab32p() (not the open-coded version) and then use writesl() or iowrite32_rep() with count=1 to write the byteswapped FIFO register without swapping it again. Arnd From gustavoars at kernel.org Tue Nov 24 14:47:05 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Tue, 24 Nov 2020 08:47:05 -0600 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201123200345.GA38546@nvidia.com> References: <20201123200345.GA38546@nvidia.com> Message-ID: <20201124144705.GK16084@embeddedor> On Mon, Nov 23, 2020 at 04:03:45PM -0400, Jason Gunthorpe wrote: > On Fri, Nov 20, 2020 at 12:21:39PM -0600, Gustavo A. R. Silva wrote: > > > IB/hfi1: Fix fall-through warnings for Clang > > IB/mlx4: Fix fall-through warnings for Clang > > IB/qedr: Fix fall-through warnings for Clang > > RDMA/mlx5: Fix fall-through warnings for Clang > > I picked these four to the rdma tree, thanks Awesome. :) Thank you, Jason. -- Gustavo From gustavoars at kernel.org Tue Nov 24 14:47:54 2020 From: gustavoars at kernel.org (Gustavo A. R. Silva) Date: Tue, 24 Nov 2020 08:47:54 -0600 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <160616392671.21180.16517492185091399884.b4-ty@kernel.org> References: <160616392671.21180.16517492185091399884.b4-ty@kernel.org> Message-ID: <20201124144754.GL16084@embeddedor> On Mon, Nov 23, 2020 at 08:38:46PM +0000, Mark Brown wrote: > On Fri, 20 Nov 2020 12:21:39 -0600, Gustavo A. R. Silva wrote: > > This series aims to fix almost all remaining fall-through warnings in > > order to enable -Wimplicit-fallthrough for Clang. > > > > In preparation to enable -Wimplicit-fallthrough for Clang, explicitly > > add multiple break/goto/return/fallthrough statements instead of just > > letting the code fall through to the next case. > > > > [...] > > Applied to > > https://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git for-next > > Thanks! > > [1/1] regulator: as3722: Fix fall-through warnings for Clang > commit: b52b417ccac4fae5b1f2ec4f1d46eb91e4493dc5 Thank you, Mark. -- Gustavo From lkp at intel.com Tue Nov 24 19:35:31 2020 From: lkp at intel.com (kernel test robot) Date: Wed, 25 Nov 2020 03:35:31 +0800 Subject: [staging:staging-testing] BUILD SUCCESS 749c1e1481e1d242ded9dd1bf210ddb7c0d22a4f Message-ID: <5fbd6083.CjJmLaKZzzCni0NH%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: 749c1e1481e1d242ded9dd1bf210ddb7c0d22a4f Merge tag 'iio-for-5.11a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next elapsed time: 722m configs tested: 112 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig sh defconfig c6x evmc6457_defconfig arm exynos_defconfig mips gpr_defconfig arm nhk8815_defconfig mips bigsur_defconfig mips jazz_defconfig powerpc pmac32_defconfig mips lemote2f_defconfig mips maltasmvp_defconfig powerpc ppc44x_defconfig powerpc mpc866_ads_defconfig mips ip32_defconfig arm multi_v5_defconfig powerpc mpc837x_mds_defconfig sh se7619_defconfig mips allyesconfig powerpc mpc832x_mds_defconfig arm badge4_defconfig powerpc stx_gp3_defconfig arm integrator_defconfig sh ecovec24_defconfig mips cavium_octeon_defconfig sh landisk_defconfig arm bcm2835_defconfig powerpc mpc8272_ads_defconfig sh edosk7760_defconfig arm at91_dt_defconfig powerpc mpc8315_rdb_defconfig mips rt305x_defconfig arc axs103_smp_defconfig mips loongson1b_defconfig powerpc arches_defconfig powerpc ppc64e_defconfig arm collie_defconfig xtensa xip_kc705_defconfig mips ar7_defconfig arm am200epdkit_defconfig arm orion5x_defconfig ia64 allmodconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig s390 allyesconfig parisc allyesconfig s390 defconfig i386 allyesconfig sparc allyesconfig sparc defconfig i386 defconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig x86_64 randconfig-a006-20201124 x86_64 randconfig-a003-20201124 x86_64 randconfig-a004-20201124 x86_64 randconfig-a005-20201124 x86_64 randconfig-a001-20201124 x86_64 randconfig-a002-20201124 i386 randconfig-a004-20201124 i386 randconfig-a003-20201124 i386 randconfig-a002-20201124 i386 randconfig-a005-20201124 i386 randconfig-a001-20201124 i386 randconfig-a006-20201124 i386 randconfig-a012-20201124 i386 randconfig-a013-20201124 i386 randconfig-a011-20201124 i386 randconfig-a016-20201124 i386 randconfig-a014-20201124 i386 randconfig-a015-20201124 riscv allyesconfig riscv allnoconfig riscv defconfig riscv allmodconfig riscv nommu_k210_defconfig riscv nommu_virt_defconfig riscv rv32_defconfig x86_64 rhel x86_64 allyesconfig x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a015-20201124 x86_64 randconfig-a011-20201124 x86_64 randconfig-a014-20201124 x86_64 randconfig-a016-20201124 x86_64 randconfig-a012-20201124 x86_64 randconfig-a013-20201124 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From keescook at chromium.org Tue Nov 24 21:25:40 2020 From: keescook at chromium.org (Kees Cook) Date: Tue, 24 Nov 2020 13:25:40 -0800 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> Message-ID: <202011241324.B3439A2@keescook> On Mon, Nov 23, 2020 at 05:32:51PM -0800, Nick Desaulniers wrote: > On Sun, Nov 22, 2020 at 8:17 AM Kees Cook wrote: > > > > On Fri, Nov 20, 2020 at 11:51:42AM -0800, Jakub Kicinski wrote: > > > If none of the 140 patches here fix a real bug, and there is no change > > > to machine code then it sounds to me like a W=2 kind of a warning. > > > > FWIW, this series has found at least one bug so far: > > https://lore.kernel.org/lkml/CAFCwf11izHF=g1mGry1fE5kvFFFrxzhPSM6qKAO8gxSp=Kr_CQ at mail.gmail.com/ > > So looks like the bulk of these are: > switch (x) { > case 0: > ++x; > default: > break; > } > > I have a patch that fixes those up for clang: > https://reviews.llvm.org/D91895 I still think this isn't right -- it's a case statement that runs off the end without an explicit flow control determination. I think Clang is right to warn for these, and GCC should also warn. -- Kees Cook From sboyd at kernel.org Wed Nov 25 00:11:31 2020 From: sboyd at kernel.org (Stephen Boyd) Date: Tue, 24 Nov 2020 16:11:31 -0800 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <20201118074812.GA5803@kozik-lap> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-2-krzk@kernel.org> <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> <20201118074812.GA5803@kozik-lap> Message-ID: <160626309137.2717324.9318376048083763040@swboyd.mtv.corp.google.com> Quoting Krzysztof Kozlowski (2020-11-17 23:48:12) > On Tue, Nov 17, 2020 at 11:41:57PM -0800, Stephen Boyd wrote: > > Quoting Krzysztof Kozlowski (2020-11-15 09:09:48) > > > COMMON_CLK even though is a user-selectable symbol, is still selected by > > > multiple other config options. COMMON_CLK should not be used when > > > legacy clocks are provided by architecture, so it correctly depends on > > > !HAVE_LEGACY_CLK. > > > > > > However it is possible to create a config which selects both COMMON_CLK > > > (by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (by SOC_RT305X) which leads to > > > > Why is SND_SUN8I_CODEC selecting COMMON_CLK? Or really, why is > > SOC_RT305X selecting HAVE_LEGACY_CLK? > > The SND_SUN8I_CODEC I fixed in following patch (I sent separately v2 of > it). > > The SOC_RT305X select HAVE_LEGACY_CLK? because it is an old, Ralink > platform, not converted to Common clock frm. Few clock operations are > defined in: arch/mips/ralink/clk.c > Ok so this patch isn't necessary then? It seems OK to select HAVE_LEGACY_CLK but not to select COMMON_CLK unless it's architecture code that can't be enabled when the other architecture code is selecting HAVE_LEGACY_CLK. From sboyd at kernel.org Wed Nov 25 00:14:41 2020 From: sboyd at kernel.org (Stephen Boyd) Date: Tue, 24 Nov 2020 16:14:41 -0800 Subject: [RFC 3/3] media: atomisp: do not select COMMON_CLK to fix builds In-Reply-To: <20201115170950.304460-4-krzk@kernel.org> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-4-krzk@kernel.org> Message-ID: <160626328163.2717324.18098835445527872342@swboyd.mtv.corp.google.com> Quoting Krzysztof Kozlowski (2020-11-15 09:09:50) > COMMON_CLK is a user-selectable option with its own dependencies. The > most important dependency is !HAVE_LEGACY_CLK. User-selectable drivers > should not select COMMON_CLK because they will create a dependency cycle > and build failures. > > Signed-off-by: Krzysztof Kozlowski This is fallout from making the COMMON_CLK symbol selectable in commit bbd7ffdbef68 ("clk: Allow the common clk framework to be selectable"). Before then we needed drivers to select the COMMON_CLK config so that the framework was enabled. Now that isn't necessary and any user-selectable options should be moved to depends syntax. Reviewed-by: Stephen Boyd From miguel.ojeda.sandonis at gmail.com Wed Nov 25 00:32:17 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Wed, 25 Nov 2020 01:32:17 +0100 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <4993259d01a0064f8bb22770503490f9252f3659.camel@HansenPartnership.com> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <1c7d7fde126bc0acf825766de64bf2f9b888f216.camel@HansenPartnership.com> <4993259d01a0064f8bb22770503490f9252f3659.camel@HansenPartnership.com> Message-ID: On Mon, Nov 23, 2020 at 9:38 PM James Bottomley wrote: > > So you think a one line patch should take one minute to produce ... I > really don't think that's grounded in reality. No, I have not said that. Please don't put words in my mouth (again). I have said *authoring* lines of *this* kind takes a minute per line. Specifically: lines fixing the fallthrough warning mechanically and repeatedly where the compiler tells you to, and doing so full-time for a month. For instance, take the following one from Gustavo. Are you really saying it takes 12 minutes (your number) to write that `break;`? diff --git a/drivers/gpu/drm/via/via_irq.c b/drivers/gpu/drm/via/via_irq.c index 24cc445169e2..a3e0fb5b8671 100644 --- a/drivers/gpu/drm/via/via_irq.c +++ b/drivers/gpu/drm/via/via_irq.c @@ -364,6 +364,7 @@ int via_wait_irq(struct drm_device *dev, void *data, struct drm_file *file_priv) irqwait->request.sequence += atomic_read(&cur_irq->irq_received); irqwait->request.type &= ~_DRM_VBLANK_RELATIVE; + break; case VIA_IRQ_ABSOLUTE: break; default: > I suppose a one line > patch only takes a minute to merge with b4 if no-one reviews or tests > it, but that's not really desirable. I have not said that either. I said reviewing and merging those are noise compared to any complex patch. Testing should be done by the author comparing codegen. > Part of what I'm trying to measure is the "and useful" bit because > that's not a given. It is useful since it makes intent clear. It also catches actual bugs, which is even more valuable. > Well, you know, subsystems are very different in terms of the amount of > patches a maintainer has to process per release cycle of the kernel. > If a maintainer is close to capacity, additional patches, however > trivial, become a problem. If a maintainer has spare cycles, trivial > patches may look easy. First of all, voluntary maintainers choose their own workload. Furthermore, we already measure capacity in the `MAINTAINERS` file: maintainers can state they can only handle a few patches. Finally, if someone does not have time for a trivial patch, they are very unlikely to have any time to review big ones. > You seem to be saying that because you find it easy to merge trivial > patches, everyone should. Again, I have not said anything of the sort. Cheers, Miguel From benjamin.poirier at gmail.com Wed Nov 25 04:42:57 2020 From: benjamin.poirier at gmail.com (Benjamin Poirier) Date: Wed, 25 Nov 2020 13:42:57 +0900 Subject: [PATCH 127/141] staging: qlge: Fix fall-through warnings for Clang In-Reply-To: <673bd9f27bcc2df8c9d12be94f54001d8066d4ab.1605896060.git.gustavoars@kernel.org> References: <673bd9f27bcc2df8c9d12be94f54001d8066d4ab.1605896060.git.gustavoars@kernel.org> Message-ID: <20201125044257.GA142382@f3> On 2020-11-20 12:39 -0600, Gustavo A. R. Silva wrote: > In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning > by explicitly adding a break statement instead of letting the code fall > through to the next case. > > Link: https://github.com/KSPP/linux/issues/115 > Signed-off-by: Gustavo A. R. Silva > --- > drivers/staging/qlge/qlge_main.c | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c > index 27da386f9d87..c41b1373dcf8 100644 > --- a/drivers/staging/qlge/qlge_main.c > +++ b/drivers/staging/qlge/qlge_main.c > @@ -1385,6 +1385,7 @@ static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err, > break; > case IB_MAC_IOCB_RSP_ERR_CRC: > stats->rx_crc_err++; > + break; > default: > break; > } In this instance, it think it would be more appropriate to remove the "default" case. From krzk at kernel.org Wed Nov 25 14:15:05 2020 From: krzk at kernel.org (Krzysztof Kozlowski) Date: Wed, 25 Nov 2020 15:15:05 +0100 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <160626309137.2717324.9318376048083763040@swboyd.mtv.corp.google.com> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-2-krzk@kernel.org> <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> <20201118074812.GA5803@kozik-lap> <160626309137.2717324.9318376048083763040@swboyd.mtv.corp.google.com> Message-ID: <20201125141505.GA77733@kozik-lap> On Tue, Nov 24, 2020 at 04:11:31PM -0800, Stephen Boyd wrote: > Quoting Krzysztof Kozlowski (2020-11-17 23:48:12) > > On Tue, Nov 17, 2020 at 11:41:57PM -0800, Stephen Boyd wrote: > > > Quoting Krzysztof Kozlowski (2020-11-15 09:09:48) > > > > COMMON_CLK even though is a user-selectable symbol, is still selected by > > > > multiple other config options. COMMON_CLK should not be used when > > > > legacy clocks are provided by architecture, so it correctly depends on > > > > !HAVE_LEGACY_CLK. > > > > > > > > However it is possible to create a config which selects both COMMON_CLK > > > > (by SND_SUN8I_CODEC) and HAVE_LEGACY_CLK (by SOC_RT305X) which leads to > > > > > > Why is SND_SUN8I_CODEC selecting COMMON_CLK? Or really, why is > > > SOC_RT305X selecting HAVE_LEGACY_CLK? > > > > The SND_SUN8I_CODEC I fixed in following patch (I sent separately v2 of > > it). > > > > The SOC_RT305X select HAVE_LEGACY_CLK? because it is an old, Ralink > > platform, not converted to Common clock frm. Few clock operations are > > defined in: arch/mips/ralink/clk.c > > > > Ok so this patch isn't necessary then? For this particular build failure - it is not necessary anymore. However there might more of such errors - just not discovered yet. Also, the clock bulk API has such ifdefs so it kind of symmetrical and consistent approach. > It seems OK to select > HAVE_LEGACY_CLK but not to select COMMON_CLK unless it's architecture > code that can't be enabled when the other architecture code is selecting > HAVE_LEGACY_CLK. Best regards, Krzysztof From sashal at kernel.org Wed Nov 25 15:35:24 2020 From: sashal at kernel.org (Sasha Levin) Date: Wed, 25 Nov 2020 10:35:24 -0500 Subject: [PATCH AUTOSEL 5.9 07/33] staging: ralink-gdma: fix kconfig dependency bug for DMA_RALINK In-Reply-To: <20201125153550.810101-1-sashal@kernel.org> References: <20201125153550.810101-1-sashal@kernel.org> Message-ID: <20201125153550.810101-7-sashal@kernel.org> From: Necip Fazil Yildiran [ Upstream commit 06ea594051707c6b8834ef5b24e9b0730edd391b ] When DMA_RALINK is enabled and DMADEVICES is disabled, it results in the following Kbuild warnings: WARNING: unmet direct dependencies detected for DMA_ENGINE Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] WARNING: unmet direct dependencies detected for DMA_VIRTUAL_CHANNELS Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] The reason is that DMA_RALINK selects DMA_ENGINE and DMA_VIRTUAL_CHANNELS without depending on or selecting DMADEVICES while DMA_ENGINE and DMA_VIRTUAL_CHANNELS are subordinate to DMADEVICES. This can also fail building the kernel as demonstrated in a bug report. Honor the kconfig dependency to remove unmet direct dependency warnings and avoid any potential build failures. Link: https://bugzilla.kernel.org/show_bug.cgi?id=210055 Signed-off-by: Necip Fazil Yildiran Link: https://lore.kernel.org/r/20201104181522.43567-1-fazilyildiran at gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/ralink-gdma/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/ralink-gdma/Kconfig b/drivers/staging/ralink-gdma/Kconfig index 54e8029e6b1af..0017376234e28 100644 --- a/drivers/staging/ralink-gdma/Kconfig +++ b/drivers/staging/ralink-gdma/Kconfig @@ -2,6 +2,7 @@ config DMA_RALINK tristate "RALINK DMA support" depends on RALINK && !SOC_RT288X + depends on DMADEVICES select DMA_ENGINE select DMA_VIRTUAL_CHANNELS -- 2.27.0 From sashal at kernel.org Wed Nov 25 15:36:22 2020 From: sashal at kernel.org (Sasha Levin) Date: Wed, 25 Nov 2020 10:36:22 -0500 Subject: [PATCH AUTOSEL 5.4 07/23] staging: ralink-gdma: fix kconfig dependency bug for DMA_RALINK In-Reply-To: <20201125153638.810419-1-sashal@kernel.org> References: <20201125153638.810419-1-sashal@kernel.org> Message-ID: <20201125153638.810419-7-sashal@kernel.org> From: Necip Fazil Yildiran [ Upstream commit 06ea594051707c6b8834ef5b24e9b0730edd391b ] When DMA_RALINK is enabled and DMADEVICES is disabled, it results in the following Kbuild warnings: WARNING: unmet direct dependencies detected for DMA_ENGINE Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] WARNING: unmet direct dependencies detected for DMA_VIRTUAL_CHANNELS Depends on [n]: DMADEVICES [=n] Selected by [y]: - DMA_RALINK [=y] && STAGING [=y] && RALINK [=y] && !SOC_RT288X [=n] The reason is that DMA_RALINK selects DMA_ENGINE and DMA_VIRTUAL_CHANNELS without depending on or selecting DMADEVICES while DMA_ENGINE and DMA_VIRTUAL_CHANNELS are subordinate to DMADEVICES. This can also fail building the kernel as demonstrated in a bug report. Honor the kconfig dependency to remove unmet direct dependency warnings and avoid any potential build failures. Link: https://bugzilla.kernel.org/show_bug.cgi?id=210055 Signed-off-by: Necip Fazil Yildiran Link: https://lore.kernel.org/r/20201104181522.43567-1-fazilyildiran at gmail.com Signed-off-by: Greg Kroah-Hartman Signed-off-by: Sasha Levin --- drivers/staging/ralink-gdma/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/ralink-gdma/Kconfig b/drivers/staging/ralink-gdma/Kconfig index 54e8029e6b1af..0017376234e28 100644 --- a/drivers/staging/ralink-gdma/Kconfig +++ b/drivers/staging/ralink-gdma/Kconfig @@ -2,6 +2,7 @@ config DMA_RALINK tristate "RALINK DMA support" depends on RALINK && !SOC_RT288X + depends on DMADEVICES select DMA_ENGINE select DMA_VIRTUAL_CHANNELS -- 2.27.0 From kuba at kernel.org Wed Nov 25 16:24:05 2020 From: kuba at kernel.org (Jakub Kicinski) Date: Wed, 25 Nov 2020 08:24:05 -0800 Subject: [Intel-wired-lan] [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: References: <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> <20201123130348.GA3119@embeddedor> <8f5611bb015e044fa1c0a48147293923c2d904e4.camel@HansenPartnership.com> <202011241327.BB28F12F6@keescook> Message-ID: <20201125082405.1d8c23dc@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> On Wed, 25 Nov 2020 04:24:27 -0800 Nick Desaulniers wrote: > I even agree that most of the churn comes from > > case 0: > ++x; > default: > break; And just to spell it out, case ENUM_VALUE1: bla(); break; case ENUM_VALUE2: bla(); default: break; is a fairly idiomatic way of indicating that not all values of the enum are expected to be handled by the switch statement. I really hope the Clang folks are reasonable and merge your patch. > If trivial patches are adding too much to your workload, consider > training a co-maintainer or asking for help from one of your reviewers > whom you trust. I don't doubt it's hard to find maintainers, but > existing maintainers should go out of their way to entrust > co-maintainers especially when they find their workload becomes too > high. And reviewing/picking up trivial patches is probably a great > way to get started. If we allow too much knowledge of any one > subsystem to collect with one maintainer, what happens when that > maintainer leaves the community (which, given a finite lifespan, is an > inevitability)? The burn out point is about enjoying your work and feeling that it matters. It really doesn't make much difference if you're doing something you don't like for 12 hours every day or only in shifts with another maintainer. You'll dislike it either way. Applying a real patch set and then getting a few follow ups the next day for trivial coding things like fallthrough missing or static missing, just because I didn't have the full range of compilers to check with before applying makes me feel pretty shitty, like I'm not doing a good job. YMMV. From miguel.ojeda.sandonis at gmail.com Wed Nov 25 17:04:15 2020 From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda) Date: Wed, 25 Nov 2020 18:04:15 +0100 Subject: [Intel-wired-lan] [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201125082405.1d8c23dc@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> <20201123130348.GA3119@embeddedor> <8f5611bb015e044fa1c0a48147293923c2d904e4.camel@HansenPartnership.com> <202011241327.BB28F12F6@keescook> <20201125082405.1d8c23dc@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: On Wed, Nov 25, 2020 at 5:24 PM Jakub Kicinski wrote: > > And just to spell it out, > > case ENUM_VALUE1: > bla(); > break; > case ENUM_VALUE2: > bla(); > default: > break; > > is a fairly idiomatic way of indicating that not all values of the enum > are expected to be handled by the switch statement. It looks like a benign typo to me -- `ENUM_VALUE2` does not follow the same pattern like `ENUM_VALUE1`. To me, the presence of the `default` is what indicates (explicitly) that not everything is handled. > Applying a real patch set and then getting a few follow ups the next day > for trivial coding things like fallthrough missing or static missing, > just because I didn't have the full range of compilers to check with > before applying makes me feel pretty shitty, like I'm not doing a good > job. YMMV. The number of compilers, checkers, static analyzers, tests, etc. we use keeps going up. That, indeed, means maintainers will miss more things (unless maintainers do more work than before). But catching bugs before they happen is *not* a bad thing. Perhaps we could encourage more rebasing in -next (while still giving credit to bots and testers) to avoid having many fixing commits afterwards, but that is orthogonal. I really don't think we should encourage the feeling that a maintainer is doing a bad job if they don't catch everything on their reviews. Any review is worth it. Maintainers, in the end, are just the "guaranteed" reviewers that decide when the code looks reasonable enough. They should definitely not feel pressured to be perfect. Cheers, Miguel From ritundailb111 at gmail.com Wed Nov 25 19:27:51 2020 From: ritundailb111 at gmail.com (Dailborh R.) Date: Wed, 25 Nov 2020 19:27:51 +0000 Subject: Please reply to me Message-ID: <5fbeb048.1c69fb81.80257.d7bb@mx.google.com> I'm Dailborh R. from US. I picked interest in you and I would like to know more about you and establish relationship with you. i will wait for your response. thank you. From ritundailb333 at gmail.com Wed Nov 25 19:45:46 2020 From: ritundailb333 at gmail.com (Dailborh R.) Date: Wed, 25 Nov 2020 19:45:46 +0000 Subject: Please reply to me Message-ID: <5fbeb481.1c69fb81.29222.d034@mx.google.com> I'm Dailborh R. from US. I picked interest in you and I would like to know more about you and establish relationship with you. i will wait for your response. thank you. From ndesaulniers at google.com Wed Nov 25 22:09:08 2020 From: ndesaulniers at google.com (Nick Desaulniers) Date: Wed, 25 Nov 2020 14:09:08 -0800 Subject: [Intel-wired-lan] [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <20201125082405.1d8c23dc@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> References: <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <9b57fd4914b46f38d54087d75e072d6e947cb56d.camel@HansenPartnership.com> <0147972a72bc13f3629de8a32dee6f1f308994b5.camel@HansenPartnership.com> <20201123130348.GA3119@embeddedor> <8f5611bb015e044fa1c0a48147293923c2d904e4.camel@HansenPartnership.com> <202011241327.BB28F12F6@keescook> <20201125082405.1d8c23dc@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> Message-ID: On Wed, Nov 25, 2020 at 8:24 AM Jakub Kicinski wrote: > > Applying a real patch set and then getting a few follow ups the next day > for trivial coding things like fallthrough missing or static missing, > just because I didn't have the full range of compilers to check with > before applying makes me feel pretty shitty, like I'm not doing a good > job. YMMV. I understand. Everyone feels that way, except maybe Bond villains and robots. My advice in that case is don't take it personally. We're working with a language that's more error prone relative to others. While one would like to believe they are flawless, over time they can't beat the aggregate statistics. A balance between Imposter Syndrome and Dunning Kruger is walked by all software developers, and the fear of making mistakes in public is one of the number one reasons folks don't take the plunge contributing to open source software or even the kernel. My advice to them is "don't sweat the small stuff." -- Thanks, ~Nick Desaulniers From ecree.xilinx at gmail.com Wed Nov 25 23:02:40 2020 From: ecree.xilinx at gmail.com (Edward Cree) Date: Wed, 25 Nov 2020 23:02:40 +0000 Subject: [PATCH 000/141] Fix fall-through warnings for Clang In-Reply-To: <202011241324.B3439A2@keescook> References: <20201120105344.4345c14e@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011201129.B13FDB3C@keescook> <20201120115142.292999b2@kicinski-fedora-pc1c0hjn.dhcp.thefacebook.com> <202011220816.8B6591A@keescook> <202011241324.B3439A2@keescook> Message-ID: <99a9ffd7-6356-b81d-6e08-7ed74b6fb82c@gmail.com> On 24/11/2020 21:25, Kees Cook wrote: > I still think this isn't right -- it's a case statement that runs off > the end without an explicit flow control determination. Proves too much ? for instance case foo: case bar: thing; break; doesn't require a fallthrough; after case foo:, and afaik no-one is suggesting it should. Yet it, too, is "a case statement that runs off the end without an explicit flow control determination". -ed From financialcapability6 at gmail.com Wed Nov 25 13:51:26 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Wed, 25 Nov 2020 05:51:26 -0800 Subject: Corporate and Personal Loan +, Message-ID: <20201126014318.C89262E1C9@silver.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From financialcapability6 at gmail.com Thu Nov 26 12:52:50 2020 From: financialcapability6 at gmail.com (Investment Corporate) Date: Thu, 26 Nov 2020 04:52:50 -0800 Subject: Corporate and Personal Loan +,, Message-ID: <20201126130251.C68228770B@hemlock.osuosl.org> Hello devel at driverdev.osuosl.org We are Base Investment Company offering Corporate and Personal Loan at 3% Interest Rate for a duration of 10Years. We also pay 1% commission to brokers, who introduce project owners for finance or other opportunities. Please get back to me if you are interested for more details. Yours faithfully, Hashim Murrah From lkp at intel.com Thu Nov 26 20:16:07 2020 From: lkp at intel.com (kernel test robot) Date: Fri, 27 Nov 2020 04:16:07 +0800 Subject: [staging:staging-testing] BUILD SUCCESS 1de16e38f1fdbfd9d842a06919098813ed93abf7 Message-ID: <5fc00d07.XoHW/0VlsbumXNYL%lkp@intel.com> tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git staging-testing branch HEAD: 1de16e38f1fdbfd9d842a06919098813ed93abf7 staging: mt7621-pci: remove 'RALINK_PCI_IMBASEBAR0_ADDR' register elapsed time: 721m configs tested: 114 configs skipped: 2 The following configs have been built successfully. More configs may be tested in the coming days. gcc tested configs: arm defconfig arm64 allyesconfig arm64 defconfig arm allyesconfig arm allmodconfig x86_64 allyesconfig arm shmobile_defconfig arm u8500_defconfig xtensa iss_defconfig sh se7619_defconfig arc haps_hs_smp_defconfig arm mini2440_defconfig sh se7343_defconfig powerpc canyonlands_defconfig powerpc currituck_defconfig arm mvebu_v7_defconfig arm vf610m4_defconfig arm tango4_defconfig mips nlm_xlr_defconfig arm multi_v4t_defconfig ia64 allmodconfig sh espt_defconfig arm cerfcube_defconfig arm trizeps4_defconfig s390 defconfig arm efm32_defconfig xtensa virt_defconfig s390 allyesconfig sh sh7785lcr_32bit_defconfig mips maltasmvp_defconfig m68k multi_defconfig mips workpad_defconfig arm at91_dt_defconfig powerpc tqm8555_defconfig s390 alldefconfig powerpc mpc512x_defconfig arm orion5x_defconfig sh ecovec24-romimage_defconfig riscv alldefconfig powerpc taishan_defconfig i386 defconfig sh se7705_defconfig m68k alldefconfig arm corgi_defconfig mips nlm_xlp_defconfig arm nhk8815_defconfig arm ebsa110_defconfig powerpc amigaone_defconfig powerpc mpc834x_itxgp_defconfig arc nsimosci_hs_defconfig ia64 defconfig ia64 allyesconfig m68k allmodconfig m68k defconfig m68k allyesconfig nios2 defconfig arc allyesconfig nds32 allnoconfig c6x allyesconfig nds32 defconfig nios2 allyesconfig csky defconfig alpha defconfig alpha allyesconfig xtensa allyesconfig h8300 allyesconfig arc defconfig sh allmodconfig parisc defconfig parisc allyesconfig i386 allyesconfig sparc allyesconfig sparc defconfig mips allyesconfig mips allmodconfig powerpc allyesconfig powerpc allmodconfig powerpc allnoconfig x86_64 randconfig-a006-20201126 x86_64 randconfig-a003-20201126 x86_64 randconfig-a004-20201126 x86_64 randconfig-a005-20201126 x86_64 randconfig-a001-20201126 x86_64 randconfig-a002-20201126 i386 randconfig-a004-20201126 i386 randconfig-a003-20201126 i386 randconfig-a002-20201126 i386 randconfig-a005-20201126 i386 randconfig-a001-20201126 i386 randconfig-a006-20201126 i386 randconfig-a012-20201126 i386 randconfig-a013-20201126 i386 randconfig-a011-20201126 i386 randconfig-a016-20201126 i386 randconfig-a014-20201126 i386 randconfig-a015-20201126 riscv nommu_k210_defconfig riscv allyesconfig riscv nommu_virt_defconfig riscv allnoconfig riscv defconfig riscv rv32_defconfig riscv allmodconfig x86_64 rhel x86_64 rhel-7.6-kselftests x86_64 defconfig x86_64 rhel-8.3 x86_64 kexec clang tested configs: x86_64 randconfig-a015-20201126 x86_64 randconfig-a011-20201126 x86_64 randconfig-a014-20201126 x86_64 randconfig-a016-20201126 x86_64 randconfig-a012-20201126 x86_64 randconfig-a013-20201126 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all at lists.01.org From colin.king at canonical.com Thu Nov 26 22:46:02 2020 From: colin.king at canonical.com (Colin King) Date: Thu, 26 Nov 2020 22:46:02 +0000 Subject: [PATCH] staging: most: Fix spelling mistake "tranceiver" -> "transceiver" Message-ID: <20201126224602.13878-1-colin.king@canonical.com> From: Colin Ian King There is a spelling mistake in the Kconfig help text. Fix it. Signed-off-by: Colin Ian King --- drivers/staging/most/i2c/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/most/i2c/Kconfig b/drivers/staging/most/i2c/Kconfig index 19a094b5bee0..ff64283cbad1 100644 --- a/drivers/staging/most/i2c/Kconfig +++ b/drivers/staging/most/i2c/Kconfig @@ -7,7 +7,7 @@ config MOST_I2C tristate "I2C" depends on I2C help - Say Y here if you want to connect via I2C to network tranceiver. + Say Y here if you want to connect via I2C to network transceiver. To compile this driver as a module, choose M here: the module will be called most_i2c. -- 2.29.2 From ezequiel at collabora.com Thu Nov 26 23:21:11 2020 From: ezequiel at collabora.com (Ezequiel Garcia) Date: Thu, 26 Nov 2020 20:21:11 -0300 Subject: [PATCH v3] media: cedrus: Add support for VP8 decoding In-Reply-To: <20201110223540.4105284-1-jernej.skrabec@siol.net> References: <20201110223540.4105284-1-jernej.skrabec@siol.net> Message-ID: <1496f292eadc62a3ab585a89cf9b997ce4a1d799.camel@collabora.com> Hi Jernej, Emmanuel, Thanks for the patch. On Tue, 2020-11-10 at 23:35 +0100, Jernej Skrabec wrote: > VP8 in Cedrus shares same engine as H264. > > Note that it seems necessary to call bitstream parsing functions, > to parse frame header, otherwise decoded image is garbage. This is > contrary to what is driver supposed to do. However, values are not > really used, so this might be acceptable. It's possible that bitstream > parsing functions set some internal VPU state, which is later necessary > for proper decoding. Biggest suspect is "VP8 probs update" trigger. > > Signed-off-by: Jernej Skrabec > [addressed issues from reviewer] > Signed-off-by: Emmanuel Gil Peyrot > --- > Changes in v3: > - addressed comments from Ezequiel Garcia - new comments, > using new macros from VP8 UAPI, new function for waiting > on bit to be set > Changes in v2: > - rebased on top of current linux-media master branch > > NOTE: This now depends on following patch: > https://patchwork.linuxtv.org/project/linux-media/patch/20201108202021.4187-1-linkmauve at linkmauve.fr/ > The patch looks fairly good, so let's wait and see what Hans, Paul and Maxime think about it. FWIW, my humble Reviewed-by: Ezequiel Garcia It would be good to make sure this doesn't regress v4l2-compliance, or cause some regression in decoding. Not really a blocker to merge this, but I'm thinking that now that we have Fluster for conformance testing, we could add the VP8 vectors and use them against Cedrus and Hantro: https://chromium.googlesource.com/webm/vp8-test-vectors/+/refs/heads/master Thanks, Ezequiel > drivers/staging/media/sunxi/cedrus/Makefile | 3 +- > drivers/staging/media/sunxi/cedrus/cedrus.c | 8 + > drivers/staging/media/sunxi/cedrus/cedrus.h | 24 + > .../staging/media/sunxi/cedrus/cedrus_dec.c | 5 + > .../staging/media/sunxi/cedrus/cedrus_hw.c | 2 + > .../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++ > .../staging/media/sunxi/cedrus/cedrus_video.c | 9 + > .../staging/media/sunxi/cedrus/cedrus_vp8.c | 907 ++++++++++++++++++ > 8 files changed, 1037 insertions(+), 1 deletion(-) > create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c > From jernej.skrabec at siol.net Thu Nov 26 23:40:31 2020 From: jernej.skrabec at siol.net (Jernej =?utf-8?B?xaBrcmFiZWM=?=) Date: Fri, 27 Nov 2020 00:40:31 +0100 Subject: [PATCH v3] media: cedrus: Add support for VP8 decoding In-Reply-To: <1496f292eadc62a3ab585a89cf9b997ce4a1d799.camel@collabora.com> References: <20201110223540.4105284-1-jernej.skrabec@siol.net> <1496f292eadc62a3ab585a89cf9b997ce4a1d799.camel@collabora.com> Message-ID: <2282897.HYN9I3zZbb@kista> Hi! Dne petek, 27. november 2020 ob 00:21:11 CET je Ezequiel Garcia napisal(a): > Hi Jernej, Emmanuel, > > Thanks for the patch. > > On Tue, 2020-11-10 at 23:35 +0100, Jernej Skrabec wrote: > > VP8 in Cedrus shares same engine as H264. > > > > Note that it seems necessary to call bitstream parsing functions, > > to parse frame header, otherwise decoded image is garbage. This is > > contrary to what is driver supposed to do. However, values are not > > really used, so this might be acceptable. It's possible that bitstream > > parsing functions set some internal VPU state, which is later necessary > > for proper decoding. Biggest suspect is "VP8 probs update" trigger. > > > > Signed-off-by: Jernej Skrabec > > [addressed issues from reviewer] > > Signed-off-by: Emmanuel Gil Peyrot > > --- > > Changes in v3: > > - addressed comments from Ezequiel Garcia - new comments, > > using new macros from VP8 UAPI, new function for waiting > > on bit to be set > > Changes in v2: > > - rebased on top of current linux-media master branch > > > > NOTE: This now depends on following patch: > > https://patchwork.linuxtv.org/project/linux-media/patch/ 20201108202021.4187-1-linkmauve at linkmauve.fr/ > > > > The patch looks fairly good, so let's wait and see > what Hans, Paul and Maxime think about it. > > FWIW, my humble Reviewed-by: Ezequiel Garcia Thanks! > > It would be good to make sure this doesn't regress > v4l2-compliance, or cause some regression in decoding. I didn't include v4l2-compliance here, but it was in previous revisions. This revision has just cosmetics. Not sure how it could cause any regression since it's pretty standalone. > > Not really a blocker to merge this, but I'm thinking > that now that we have Fluster for conformance testing, > we could add the VP8 vectors and use them against > Cedrus and Hantro: > > https://chromium.googlesource.com/webm/vp8-test-vectors/+/refs/heads/master I tested VP8 test vectors with initial version of this decoder by hand and all videos were properly decoded as far as I can tell. But automated testing is always welcome. Best regards, Jernej > > Thanks, > Ezequiel > > > drivers/staging/media/sunxi/cedrus/Makefile | 3 +- > > drivers/staging/media/sunxi/cedrus/cedrus.c | 8 + > > drivers/staging/media/sunxi/cedrus/cedrus.h | 24 + > > .../staging/media/sunxi/cedrus/cedrus_dec.c | 5 + > > .../staging/media/sunxi/cedrus/cedrus_hw.c | 2 + > > .../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++ > > .../staging/media/sunxi/cedrus/cedrus_video.c | 9 + > > .../staging/media/sunxi/cedrus/cedrus_vp8.c | 907 ++++++++++++++++++ > > 8 files changed, 1037 insertions(+), 1 deletion(-) > > create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c > > > > From ezequiel at collabora.com Thu Nov 26 23:39:40 2020 From: ezequiel at collabora.com (Ezequiel Garcia) Date: Thu, 26 Nov 2020 20:39:40 -0300 Subject: [PATCH v3] media: cedrus: Add support for VP8 decoding In-Reply-To: <2282897.HYN9I3zZbb@kista> References: <20201110223540.4105284-1-jernej.skrabec@siol.net> <1496f292eadc62a3ab585a89cf9b997ce4a1d799.camel@collabora.com> <2282897.HYN9I3zZbb@kista> Message-ID: <726ab182da7776bdb4f7205483442ce262293b57.camel@collabora.com> On Fri, 2020-11-27 at 00:40 +0100, Jernej ?krabec wrote: > Hi! > > Dne petek, 27. november 2020 ob 00:21:11 CET je Ezequiel Garcia napisal(a): > > Hi Jernej, Emmanuel, > > > > Thanks for the patch. > > > > On Tue, 2020-11-10 at 23:35 +0100, Jernej Skrabec wrote: > > > VP8 in Cedrus shares same engine as H264. > > > > > > Note that it seems necessary to call bitstream parsing functions, > > > to parse frame header, otherwise decoded image is garbage. This is > > > contrary to what is driver supposed to do. However, values are not > > > really used, so this might be acceptable. It's possible that bitstream > > > parsing functions set some internal VPU state, which is later necessary > > > for proper decoding. Biggest suspect is "VP8 probs update" trigger. > > > > > > Signed-off-by: Jernej Skrabec > > > [addressed issues from reviewer] > > > Signed-off-by: Emmanuel Gil Peyrot > > > --- > > > Changes in v3: > > > - addressed comments from Ezequiel Garcia - new comments, > > > using new macros from VP8 UAPI, new function for waiting > > > on bit to be set > > > Changes in v2: > > > - rebased on top of current linux-media master branch > > > > > > NOTE: This now depends on following patch: > > > https://patchwork.linuxtv.org/project/linux-media/patch/ > 20201108202021.4187-1-linkmauve at linkmauve.fr/ > > > > The patch looks fairly good, so let's wait and see > > what Hans, Paul and Maxime think about it. > > > > FWIW, my humble Reviewed-by: Ezequiel Garcia > > Thanks! > > > It would be good to make sure this doesn't regress > > v4l2-compliance, or cause some regression in decoding. > > I didn't include v4l2-compliance here, but it was in previous revisions. This > revision has just cosmetics. Not sure how it could cause any regression since > it's pretty standalone. > Yes, indeed. > > Not really a blocker to merge this, but I'm thinking > > that now that we have Fluster for conformance testing, > > we could add the VP8 vectors and use them against > > Cedrus and Hantro: > > > > https://chromium.googlesource.com/webm/vp8-test-vectors/+/refs/heads/master > > I tested VP8 test vectors with initial version of this decoder by hand and all > videos were properly decoded as far as I can tell. But automated testing is > always welcome. > More the reason to consider this safe to merge! Thanks, Ezequiel > Best regards, > Jernej > > > Thanks, > > Ezequiel > > > > > drivers/staging/media/sunxi/cedrus/Makefile | 3 +- > > > drivers/staging/media/sunxi/cedrus/cedrus.c | 8 + > > > drivers/staging/media/sunxi/cedrus/cedrus.h | 24 + > > > .../staging/media/sunxi/cedrus/cedrus_dec.c | 5 + > > > .../staging/media/sunxi/cedrus/cedrus_hw.c | 2 + > > > .../staging/media/sunxi/cedrus/cedrus_regs.h | 80 ++ > > > .../staging/media/sunxi/cedrus/cedrus_video.c | 9 + > > > .../staging/media/sunxi/cedrus/cedrus_vp8.c | 907 ++++++++++++++++++ > > > 8 files changed, 1037 insertions(+), 1 deletion(-) > > > create mode 100644 drivers/staging/media/sunxi/cedrus/cedrus_vp8.c > > > > > From pt at hinewdubai.pw Fri Nov 27 12:46:23 2020 From: pt at hinewdubai.pw (Anca Larisa Burneci) Date: 27 Nov 2020 04:46:23 -0800 Subject: new order & signed Profoma Invoice Message-ID: <20201127044623.3698388985224E9C@hinewdubai.pw> Hello Sir, Did you receive my last email? Please send confirmation of our new order attached urgently. Also see attached the signed Proforma Invoice of our last Order. Regards Anca Larisa Burneci DongweHealth Products Manufacture Co., Ltd. No.228 Shihui Rd, Songjiang,CAMBODIA Mobile: +81-13386019828 Fax: +81-21-57784148 E-mail: import at dweh.com -------------- next part -------------- A non-text attachment was scrubbed... Name: PO348578.jar Type: application/java-archive Size: 89306 bytes Desc: not available URL: From sboyd at kernel.org Fri Nov 27 20:19:12 2020 From: sboyd at kernel.org (Stephen Boyd) Date: Fri, 27 Nov 2020 12:19:12 -0800 Subject: [PATCH 1/3] clk: fix redefinition of clk_prepare on MIPS with HAVE_LEGACY_CLK In-Reply-To: <20201125141505.GA77733@kozik-lap> References: <20201115170950.304460-1-krzk@kernel.org> <20201115170950.304460-2-krzk@kernel.org> <160568531746.60232.15496517544781609246@swboyd.mtv.corp.google.com> <20201118074812.GA5803@kozik-lap> <160626309137.2717324.9318376048083763040@swboyd.mtv.corp.google.com> <20201125141505.GA77733@kozik-lap> Message-ID: <160650835295.2717324.6223337132204167294@swboyd.mtv.corp.google.com> Quoting Krzysztof Kozlowski (2020-11-25 06:15:05) > On Tue, Nov 24, 2020 at 04:11:31PM -0800, Stephen Boyd wrote: > > > > Ok so this patch isn't necessary then? > > For this particular build failure - it is not necessary anymore. > > However there might more of such errors - just not discovered yet. Also, > the clock bulk API has such ifdefs so it kind of symmetrical and > consistent approach. > Ok. Patches always welcome. From reni at linkbg.com Sat Nov 28 00:13:53 2020 From: reni at linkbg.com (L. Wanczyk) Date: Sat, 28 Nov 2020 01:13:53 +0100 Subject: CONGTRATULATION!! Message-ID: Hello, I'm Mrs. Mavis Wanczyk, the mega winner of $758 Million in Mega Millions Jackpot, I am donating to 20 random individuals if you get this email then your email was selected after a spin ball. I have spread most of my wealth over a number of charities and organizations. I have voluntarily decided to donate the sum of $8 Million USD to you as one of the selected 5, to verify my winnings via the YouTube page below. WATCH ME HERE: https://www.youtube.com/watch? v=7kWnqvJM1mM THIS IS YOUR DONATION CODE: F207162//2020 Reply with the DONATION CODE to this email: maviswanczykd at aol.com Hope to make you and your family happy. Regards, Mrs. Mavis L. Wanczyk From reni at linkbg.com Sat Nov 28 00:13:53 2020 From: reni at linkbg.com (L. Wanczyk) Date: Sat, 28 Nov 2020 01:13:53 +0100 Subject: CONGTRATULATION!! Message-ID: Hello, I'm Mrs. Mavis Wanczyk, the mega winner of $758 Million in Mega Millions Jackpot, I am donating to 20 random individuals if you get this email then your email was selected after a spin ball. I have spread most of my wealth over a number of charities and organizations. I have voluntarily decided to donate the sum of $8 Million USD to you as one of the selected 5, to verify my winnings via the YouTube page below. WATCH ME HERE: https://www.youtube.com/watch? v=7kWnqvJM1mM THIS IS YOUR DONATION CODE: F207162//2020 Reply with the DONATION CODE to this email: maviswanczykd at aol.com Hope to make you and your family happy. Regards, Mrs. Mavis L. Wanczyk From reni at linkbg.com Sat Nov 28 00:18:27 2020 From: reni at linkbg.com (L. Wanczyk) Date: Sat, 28 Nov 2020 01:18:27 +0100 Subject: CONGTRATULATION!! Message-ID: Hello, I'm Mrs. Mavis Wanczyk, the mega winner of $758 Million in Mega Millions Jackpot, I am donating to 20 random individuals if you get this email then your email was selected after a spin ball. I have spread most of my wealth over a number of charities and organizations. I have voluntarily decided to donate the sum of $8 Million USD to you as one of the selected 5, to verify my winnings via the YouTube page below. WATCH ME HERE: https://www.youtube.com/watch? v=7kWnqvJM1mM THIS IS YOUR DONATION CODE: F207162//2020 Reply with the DONATION CODE to this email: maviswanczykd at aol.com Hope to make you and your family happy. Regards, Mrs. Mavis L. Wanczyk From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:20 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:20 +0100 Subject: [PATCH v2 00/19] Allwinner MIPI CSI-2 support for A31/V3s/A83T Message-ID: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> This series introduces support for MIPI CSI-2, with the A31 controller that is found on most SoCs (A31, V3s and probably V5) as well as the A83T-specific controller. While the former uses the same MIPI D-PHY that is already supported for DSI, the latter embeds its own D-PHY. In order to distinguish the use of the D-PHY between Rx mode (for MIPI CSI-2) and Tx mode (for MIPI DSI), a submode is introduced for D-PHY in the PHY API. This allows adding Rx support in the A31 D-PHY driver. A few changes and fixes are applied to the A31 CSI controller driver, in order to support the MIPI CSI-2 use-case. Changes since v1: - reworked fwnode and media graph on the CSI controller end to have one port per interface, which solves the bus type representation issue; - removed unused IRQ handlers in the MIPI CSI-2 bridges; - avoided the use of devm_regmap_init_mmio_clk; - deasserted reset before enabling clocks; - fixed reported return code issues (ret |=, missing checks); - applied requested cosmetic changes (backward goto, etc); - switched over to runtime PM for the mipi csi-2 bridge drivers; - selected PHY_SUN6I_MIPI_DPHY in Kconfig for sun6i-mipi-csi2; - registered nodes with mipi csi-2 bridge subdevs; - used V4L2 format info instead of switch/case for sun6i-csi bpp; - fixed device-tree bindings as requested (useless properties, license); - fixed mipi bridge dt instances names; - added PHY API documentation about mode/power on order requirement; - fixed clock error return code in d-phy code; - fixed D-PHY mode check in d-phy code; - added MAINTAINERS entries for the new drivers; - added V4L2 compliance results; - added various comments and rework commit mesages as requested. V4L2 compliance runs are available below: # sun6i-csi + sun6i-mipi-csi2 + ov5648 v4l2-compliance SHA: not available, 32 bits Compliance test for sun6i-video device /dev/video0: Driver Info: Driver name : sun6i-video Card type : sun6i-csi Bus info : platform:camera Driver version : 5.10.0 Capabilities : 0x84200001 Video Capture Streaming Extended Pix Format Device Capabilities Device Caps : 0x04200001 Video Capture Streaming Extended Pix Format Media Driver Info: Driver name : sun6i-csi Model : Allwinner Video Capture Device Serial : Bus info : platform:1cb0000.camera Media version : 5.10.0 Hardware revision: 0x00000000 (0) Driver version : 5.10.0 Interface Info: ID : 0x03000004 Type : V4L Video Entity Info: ID : 0x00000001 (1) Name : sun6i-csi Function : V4L2 I/O Pad 0x01000002 : 0: Sink Pad 0x01000003 : 1: Sink Link 0x0200000d: from remote pad 0x1000008 of entity 'sun6i-mipi-csi2': Data, Enabled Required ioctls: test MC information (see 'Media Driver Info' above): OK warn: v4l2-compliance.cpp(633): media bus_info 'platform:1cb0000.camera' differs from V4L2 bus_info 'platform:camera' test VIDIOC_QUERYCAP: OK Allow for multiple opens: test second /dev/video0 open: OK warn: v4l2-compliance.cpp(633): media bus_info 'platform:1cb0000.camera' differs from V4L2 bus_info 'platform:camera' test VIDIOC_QUERYCAP: OK test VIDIOC_G/S_PRIORITY: OK test for unlimited opens: OK Debug ioctls: test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported) test VIDIOC_LOG_STATUS: OK Input ioctls: test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported) test VIDIOC_ENUMAUDIO: OK (Not Supported) test VIDIOC_G/S/ENUMINPUT: OK test VIDIOC_G/S_AUDIO: OK (Not Supported) Inputs: 1 Audio Inputs: 0 Tuners: 0 Output ioctls: test VIDIOC_G/S_MODULATOR: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_ENUMAUDOUT: OK (Not Supported) test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported) test VIDIOC_G/S_AUDOUT: OK (Not Supported) Outputs: 0 Audio Outputs: 0 Modulators: 0 Input/Output configuration ioctls: test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported) test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported) test VIDIOC_G/S_EDID: OK (Not Supported) Control ioctls (Input 0): warn: v4l2-test-controls.cpp(92): Exposure: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Gain: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Exposure: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Gain: (max - min) % step != 0 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK test VIDIOC_QUERYCTRL: OK warn: v4l2-test-controls.cpp(368): Gain: returned control value 44 not a multiple of step warn: v4l2-test-controls.cpp(368): Gain: returned control value 44 not a multiple of step warn: v4l2-test-controls.cpp(368): Gain: returned control value 44 not a multiple of step warn: v4l2-test-controls.cpp(368): Gain: returned control value 44 not a multiple of step test VIDIOC_G/S_CTRL: OK warn: v4l2-test-controls.cpp(555): Gain: returned control value 44 not a multiple of step test VIDIOC_G/S/TRY_EXT_CTRLS: OK test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK test VIDIOC_G/S_JPEGCOMP: OK (Not Supported) Standard Controls: 15 Private Controls: 0 Format ioctls (Input 0): test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK test VIDIOC_G/S_PARM: OK (Not Supported) test VIDIOC_G_FBUF: OK (Not Supported) test VIDIOC_G_FMT: OK test VIDIOC_TRY_FMT: OK test VIDIOC_S_FMT: OK test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported) test Cropping: OK (Not Supported) test Composing: OK (Not Supported) test Scaling: OK Codec ioctls (Input 0): test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported) Buffer ioctls (Input 0): test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK fail: v4l2-test-buffers.cpp(755): q.export_bufs(node, q.g_type()) test VIDIOC_EXPBUF: FAIL test Requests: OK (Not Supported) Total for sun6i-video device /dev/video0: 45, Succeeded: 44, Failed: 1, Warnings: 1 # sun6i-csi + sun8i-a83t-mipi-csi2 + ov8865 v4l2-compliance SHA: not available, 32 bits Compliance test for sun6i-video device /dev/video0: Driver Info: Driver name : sun6i-video Card type : sun6i-csi Bus info : platform:camera Driver version : 5.10.0 Capabilities : 0x84200001 Video Capture Streaming Extended Pix Format Device Capabilities Device Caps : 0x04200001 Video Capture Streaming Extended Pix Format Media Driver Info: Driver name : sun6i-csi Model : Allwinner Video Capture Device Serial : Bus info : platform:1cb0000.camera Media version : 5.10.0 Hardware revision: 0x00000000 (0) Driver version : 5.10.0 Interface Info: ID : 0x03000004 Type : V4L Video Entity Info: ID : 0x00000001 (1) Name : sun6i-csi Function : V4L2 I/O Pad 0x01000002 : 0: Sink Pad 0x01000003 : 1: Sink Link 0x0200000d: from remote pad 0x1000008 of entity 'sun8i-a83t-mipi-csi2': Data, Enabled Required ioctls: test MC information (see 'Media Driver Info' above): OK warn: v4l2-compliance.cpp(633): media bus_info 'platform:1cb0000.camera' differs from V4L2 bus_info 'platform:camera' test VIDIOC_QUERYCAP: OK Allow for multiple opens: test second /dev/video0 open: OK warn: v4l2-compliance.cpp(633): media bus_info 'platform:1cb0000.camera' differs from V4L2 bus_info 'platform:camera' test VIDIOC_QUERYCAP: OK test VIDIOC_G/S_PRIORITY: OK test for unlimited opens: OK Debug ioctls: test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported) test VIDIOC_LOG_STATUS: OK Input ioctls: test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported) test VIDIOC_ENUMAUDIO: OK (Not Supported) test VIDIOC_G/S/ENUMINPUT: OK test VIDIOC_G/S_AUDIO: OK (Not Supported) Inputs: 1 Audio Inputs: 0 Tuners: 0 Output ioctls: test VIDIOC_G/S_MODULATOR: OK (Not Supported) test VIDIOC_G/S_FREQUENCY: OK (Not Supported) test VIDIOC_ENUMAUDOUT: OK (Not Supported) test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported) test VIDIOC_G/S_AUDOUT: OK (Not Supported) Outputs: 0 Audio Outputs: 0 Modulators: 0 Input/Output configuration ioctls: test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported) test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported) test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported) test VIDIOC_G/S_EDID: OK (Not Supported) Control ioctls (Input 0): warn: v4l2-test-controls.cpp(92): Exposure: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Gain: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Exposure: (max - min) % step != 0 warn: v4l2-test-controls.cpp(92): Gain: (max - min) % step != 0 test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK test VIDIOC_QUERYCTRL: OK test VIDIOC_G/S_CTRL: OK test VIDIOC_G/S/TRY_EXT_CTRLS: OK test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK test VIDIOC_G/S_JPEGCOMP: OK (Not Supported) Standard Controls: 11 Private Controls: 0 Format ioctls (Input 0): test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK test VIDIOC_G/S_PARM: OK (Not Supported) test VIDIOC_G_FBUF: OK (Not Supported) test VIDIOC_G_FMT: OK test VIDIOC_TRY_FMT: OK test VIDIOC_S_FMT: OK test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported) test Cropping: OK (Not Supported) test Composing: OK (Not Supported) test Scaling: OK Codec ioctls (Input 0): test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported) test VIDIOC_G_ENC_INDEX: OK (Not Supported) test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported) Buffer ioctls (Input 0): test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK test VIDIOC_EXPBUF: OK test Requests: OK (Not Supported) Total for sun6i-video device /dev/video0: 45, Succeeded: 45, Failed: 0, Warnings: 6 Paul Kocialkowski (19): docs: phy: Add a part about PHY mode and submode phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI CSI-2 media: sun6i-csi: Use common V4L2 format info for storage bpp media: sun6i-csi: Only configure the interface data width for parallel dt-bindings: media: sun6i-a31-csi: Add MIPI CSI-2 input port media: sun6i-csi: Add support for MIPI CSI-2 bridge input ARM: dts: sun8i: a83t: Add CSI controller ports ARM: dts: sunxi: h3/h5: Add CSI controller port for parallel input ARM: dts: sun8i: v3s: Add CSI1 controller port for parallel input arm64: dts: allwinner: a64: Add CSI controller port for parallel input dt-bindings: media: Add A31 MIPI CSI-2 bindings documentation media: sunxi: Add support for the A31 MIPI CSI-2 controller ARM: dts: sun8i: v3s: Add nodes for MIPI CSI-2 support MAINTAINERS: Add entry for the Allwinner A31 MIPI CSI-2 bridge dt-bindings: media: Add A83T MIPI CSI-2 bindings documentation media: sunxi: Add support for the A83T MIPI CSI-2 controller ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node MAINTAINERS: Add entry for the Allwinner A83T MIPI CSI-2 bridge .../media/allwinner,sun6i-a31-csi.yaml | 86 ++- .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 151 ++++ .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 147 ++++ Documentation/driver-api/phy/phy.rst | 18 + MAINTAINERS | 16 + arch/arm/boot/dts/sun8i-a83t.dtsi | 38 +- arch/arm/boot/dts/sun8i-v3s.dtsi | 77 ++ arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 + arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 9 + drivers/media/platform/sunxi/Kconfig | 2 + drivers/media/platform/sunxi/Makefile | 2 + .../platform/sunxi/sun6i-csi/sun6i_csi.c | 165 +++-- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 58 +- .../platform/sunxi/sun6i-csi/sun6i_video.c | 53 +- .../platform/sunxi/sun6i-csi/sun6i_video.h | 7 +- .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 12 + .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 591 ++++++++++++++++ .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 117 ++++ .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ .../sun8i_a83t_mipi_csi2.c | 657 ++++++++++++++++++ .../sun8i_a83t_mipi_csi2.h | 197 ++++++ drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 ++++- drivers/staging/media/rkisp1/rkisp1-isp.c | 3 +- include/linux/phy/phy-mipi-dphy.h | 13 + 28 files changed, 2620 insertions(+), 122 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:21 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:21 +0100 Subject: [PATCH v2 01/19] docs: phy: Add a part about PHY mode and submode In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-2-paul.kocialkowski@bootlin.com> Besides giving pointers to the relevant functions for PHY mode and submode configuration, this clarifies the need to set them before powering on the PHY. Signed-off-by: Paul Kocialkowski --- Documentation/driver-api/phy/phy.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/driver-api/phy/phy.rst b/Documentation/driver-api/phy/phy.rst index 8fc1ce0bb905..6cbc72707a49 100644 --- a/Documentation/driver-api/phy/phy.rst +++ b/Documentation/driver-api/phy/phy.rst @@ -195,3 +195,21 @@ DeviceTree Binding The documentation for PHY dt binding can be found @ Documentation/devicetree/bindings/phy/phy-bindings.txt + +PHY Mode and Submode +==================== + +Once a reference to a PHY is obtained by a controller, the PHY can be configured +to a PHY mode and submode. PHY modes are described in the `phy_mode` enum while +submodes are specific to the selected PHY mode. + +Mode and submode configuration is done by calling:: + + int phy_set_mode_ext(struct phy *phy, enum phy_mode mode, int submode); + +If no submode is to be configured, users can call:: + + int phy_set_mode(struct phy *phy, enum phy_mode mode); + +The PHY mode and submode must not be configured after the PHY has already been +powered on. -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:22 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:22 +0100 Subject: [PATCH v2 02/19] phy: Distinguish between Rx and Tx for MIPI D-PHY with submodes In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-3-paul.kocialkowski@bootlin.com> As some D-PHY controllers support both Rx and Tx mode, we need a way for users to explicitly request one or the other. For instance, Rx mode can be used along with MIPI CSI-2 while Tx mode can be used with MIPI DSI. Introduce new MIPI D-PHY PHY submodes to use with PHY_MODE_MIPI_DPHY. The default (zero value) is kept to Tx so only the rkisp1 driver, which uses D-PHY in Rx mode, needs to be adapted. Signed-off-by: Paul Kocialkowski Acked-by: Helen Koike --- drivers/staging/media/rkisp1/rkisp1-isp.c | 3 ++- include/linux/phy/phy-mipi-dphy.h | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/staging/media/rkisp1/rkisp1-isp.c b/drivers/staging/media/rkisp1/rkisp1-isp.c index a9715b0b7264..f1167995688a 100644 --- a/drivers/staging/media/rkisp1/rkisp1-isp.c +++ b/drivers/staging/media/rkisp1/rkisp1-isp.c @@ -914,7 +914,8 @@ static int rkisp1_mipi_csi2_start(struct rkisp1_isp *isp, phy_mipi_dphy_get_default_config(pixel_clock, isp->sink_fmt->bus_width, sensor->lanes, cfg); - phy_set_mode(sensor->dphy, PHY_MODE_MIPI_DPHY); + phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, + PHY_MIPI_DPHY_SUBMODE_RX); phy_configure(sensor->dphy, &opts); phy_power_on(sensor->dphy); diff --git a/include/linux/phy/phy-mipi-dphy.h b/include/linux/phy/phy-mipi-dphy.h index a877ffee845d..0f57ef46a8b5 100644 --- a/include/linux/phy/phy-mipi-dphy.h +++ b/include/linux/phy/phy-mipi-dphy.h @@ -6,6 +6,19 @@ #ifndef __PHY_MIPI_DPHY_H_ #define __PHY_MIPI_DPHY_H_ +/** + * enum phy_mipi_dphy_submode - MIPI D-PHY sub-mode + * + * A MIPI D-PHY can be used to transmit or receive data. + * Since some controllers can support both, the direction to enable is specified + * with the PHY sub-mode. Transmit is assumed by default with phy_set_mode. + */ + +enum phy_mipi_dphy_submode { + PHY_MIPI_DPHY_SUBMODE_TX = 0, + PHY_MIPI_DPHY_SUBMODE_RX, +}; + /** * struct phy_configure_opts_mipi_dphy - MIPI D-PHY configuration set * -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:23 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:23 +0100 Subject: [PATCH v2 03/19] phy: allwinner: phy-sun6i-mipi-dphy: Support D-PHY Rx mode for MIPI CSI-2 In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-4-paul.kocialkowski@bootlin.com> The Allwinner A31 D-PHY supports both Rx and Tx modes. While the latter is already supported and used for MIPI DSI this adds support for the former, to be used with MIPI CSI-2. This implementation is inspired by Allwinner's V3s Linux SDK implementation, which was used as a documentation base. Signed-off-by: Paul Kocialkowski --- drivers/phy/allwinner/phy-sun6i-mipi-dphy.c | 164 +++++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c index 1fa761ba6cbb..0389b6b670d6 100644 --- a/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c +++ b/drivers/phy/allwinner/phy-sun6i-mipi-dphy.c @@ -24,6 +24,14 @@ #define SUN6I_DPHY_TX_CTL_REG 0x04 #define SUN6I_DPHY_TX_CTL_HS_TX_CLK_CONT BIT(28) +#define SUN6I_DPHY_RX_CTL_REG 0x08 +#define SUN6I_DPHY_RX_CTL_EN_DBC BIT(31) +#define SUN6I_DPHY_RX_CTL_RX_CLK_FORCE BIT(24) +#define SUN6I_DPHY_RX_CTL_RX_D3_FORCE BIT(23) +#define SUN6I_DPHY_RX_CTL_RX_D2_FORCE BIT(22) +#define SUN6I_DPHY_RX_CTL_RX_D1_FORCE BIT(21) +#define SUN6I_DPHY_RX_CTL_RX_D0_FORCE BIT(20) + #define SUN6I_DPHY_TX_TIME0_REG 0x10 #define SUN6I_DPHY_TX_TIME0_HS_TRAIL(n) (((n) & 0xff) << 24) #define SUN6I_DPHY_TX_TIME0_HS_PREPARE(n) (((n) & 0xff) << 16) @@ -44,12 +52,29 @@ #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA1(n) (((n) & 0xff) << 8) #define SUN6I_DPHY_TX_TIME4_HS_TX_ANA0(n) ((n) & 0xff) +#define SUN6I_DPHY_RX_TIME0_REG 0x30 +#define SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(n) (((n) & 0xff) << 24) +#define SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(n) (((n) & 0xff) << 16) +#define SUN6I_DPHY_RX_TIME0_LP_RX(n) (((n) & 0xff) << 8) + +#define SUN6I_DPHY_RX_TIME1_REG 0x34 +#define SUN6I_DPHY_RX_TIME1_RX_DLY(n) (((n) & 0xfff) << 20) +#define SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(n) ((n) & 0xfffff) + +#define SUN6I_DPHY_RX_TIME2_REG 0x38 +#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA1(n) (((n) & 0xff) << 8) +#define SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(n) ((n) & 0xff) + +#define SUN6I_DPHY_RX_TIME3_REG 0x40 +#define SUN6I_DPHY_RX_TIME3_LPRST_DLY(n) (((n) & 0xffff) << 16) + #define SUN6I_DPHY_ANA0_REG 0x4c #define SUN6I_DPHY_ANA0_REG_PWS BIT(31) #define SUN6I_DPHY_ANA0_REG_DMPC BIT(28) #define SUN6I_DPHY_ANA0_REG_DMPD(n) (((n) & 0xf) << 24) #define SUN6I_DPHY_ANA0_REG_SLV(n) (((n) & 7) << 12) #define SUN6I_DPHY_ANA0_REG_DEN(n) (((n) & 0xf) << 8) +#define SUN6I_DPHY_ANA0_REG_SFB(n) (((n) & 3) << 2) #define SUN6I_DPHY_ANA1_REG 0x50 #define SUN6I_DPHY_ANA1_REG_VTTMODE BIT(31) @@ -92,6 +117,8 @@ struct sun6i_dphy { struct phy *phy; struct phy_configure_opts_mipi_dphy config; + + int submode; }; static int sun6i_dphy_init(struct phy *phy) @@ -105,6 +132,18 @@ static int sun6i_dphy_init(struct phy *phy) return 0; } +static int sun6i_dphy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + + if (mode != PHY_MODE_MIPI_DPHY) + return -EINVAL; + + dphy->submode = submode; + + return 0; +} + static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) { struct sun6i_dphy *dphy = phy_get_drvdata(phy); @@ -119,9 +158,8 @@ static int sun6i_dphy_configure(struct phy *phy, union phy_configure_opts *opts) return 0; } -static int sun6i_dphy_power_on(struct phy *phy) +static int sun6i_dphy_tx_power_on(struct sun6i_dphy *dphy) { - struct sun6i_dphy *dphy = phy_get_drvdata(phy); u8 lanes_mask = GENMASK(dphy->config.lanes - 1, 0); regmap_write(dphy->regs, SUN6I_DPHY_TX_CTL_REG, @@ -211,12 +249,129 @@ static int sun6i_dphy_power_on(struct phy *phy) return 0; } +static int sun6i_dphy_rx_power_on(struct sun6i_dphy *dphy) +{ + /* Physical clock rate is actually half of symbol rate with DDR. */ + unsigned long mipi_symbol_rate = dphy->config.hs_clk_rate; + unsigned long dphy_clk_rate; + unsigned int rx_dly; + unsigned int lprst_dly; + u32 value; + + dphy_clk_rate = clk_get_rate(dphy->mod_clk); + if (!dphy_clk_rate) + return -EINVAL; + + /* Hardcoded timing parameters from the Allwinner BSP. */ + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME0_REG, + SUN6I_DPHY_RX_TIME0_HS_RX_SYNC(255) | + SUN6I_DPHY_RX_TIME0_HS_RX_CLK_MISS(255) | + SUN6I_DPHY_RX_TIME0_LP_RX(255)); + + /* + * Formula from the Allwinner BSP, with hardcoded coefficients + * (probably internal divider/multiplier). + */ + rx_dly = 8 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 8)); + + /* + * The Allwinner BSP has an alternative formula for LP_RX_ULPS_WP: + * lp_ulps_wp_cnt = lp_ulps_wp_ms * lp_clk / 1000 + * but does not use it and hardcodes 255 instead. + */ + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME1_REG, + SUN6I_DPHY_RX_TIME1_RX_DLY(rx_dly) | + SUN6I_DPHY_RX_TIME1_LP_RX_ULPS_WP(255)); + + /* HS_RX_ANA0 value is hardcoded in the Allwinner BSP. */ + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME2_REG, + SUN6I_DPHY_RX_TIME2_HS_RX_ANA0(4)); + + /* + * Formula from the Allwinner BSP, with hardcoded coefficients + * (probably internal divider/multiplier). + */ + lprst_dly = 4 * (unsigned int)(dphy_clk_rate / (mipi_symbol_rate / 2)); + + regmap_write(dphy->regs, SUN6I_DPHY_RX_TIME3_REG, + SUN6I_DPHY_RX_TIME3_LPRST_DLY(lprst_dly)); + + /* Analog parameters are hardcoded in the Allwinner BSP. */ + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, + SUN6I_DPHY_ANA0_REG_PWS | + SUN6I_DPHY_ANA0_REG_SLV(7) | + SUN6I_DPHY_ANA0_REG_SFB(2)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, + SUN6I_DPHY_ANA1_REG_SVTT(4)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, + SUN6I_DPHY_ANA4_REG_DMPLVC | + SUN6I_DPHY_ANA4_REG_DMPLVD(1)); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, + SUN6I_DPHY_ANA2_REG_ENIB); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, + SUN6I_DPHY_ANA3_EN_LDOR | + SUN6I_DPHY_ANA3_EN_LDOC | + SUN6I_DPHY_ANA3_EN_LDOD); + + /* + * Delay comes from the Allwinner BSP, likely for internal regulator + * ramp-up. + */ + udelay(3); + + value = SUN6I_DPHY_RX_CTL_EN_DBC | SUN6I_DPHY_RX_CTL_RX_CLK_FORCE; + + /* + * Rx data lane force-enable bits are used as regular RX enable by the + * Allwinner BSP. + */ + if (dphy->config.lanes >= 1) + value |= SUN6I_DPHY_RX_CTL_RX_D0_FORCE; + if (dphy->config.lanes >= 2) + value |= SUN6I_DPHY_RX_CTL_RX_D1_FORCE; + if (dphy->config.lanes >= 3) + value |= SUN6I_DPHY_RX_CTL_RX_D2_FORCE; + if (dphy->config.lanes == 4) + value |= SUN6I_DPHY_RX_CTL_RX_D3_FORCE; + + regmap_write(dphy->regs, SUN6I_DPHY_RX_CTL_REG, value); + + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, + SUN6I_DPHY_GCTL_LANE_NUM(dphy->config.lanes) | + SUN6I_DPHY_GCTL_EN); + + return 0; +} + +static int sun6i_dphy_power_on(struct phy *phy) +{ + struct sun6i_dphy *dphy = phy_get_drvdata(phy); + + switch (dphy->submode) { + case PHY_MIPI_DPHY_SUBMODE_TX: + return sun6i_dphy_tx_power_on(dphy); + case PHY_MIPI_DPHY_SUBMODE_RX: + return sun6i_dphy_rx_power_on(dphy); + default: + return -EINVAL; + } +} + static int sun6i_dphy_power_off(struct phy *phy) { struct sun6i_dphy *dphy = phy_get_drvdata(phy); - regmap_update_bits(dphy->regs, SUN6I_DPHY_ANA1_REG, - SUN6I_DPHY_ANA1_REG_VTTMODE, 0); + regmap_write(dphy->regs, SUN6I_DPHY_GCTL_REG, 0); + + regmap_write(dphy->regs, SUN6I_DPHY_ANA0_REG, 0); + regmap_write(dphy->regs, SUN6I_DPHY_ANA1_REG, 0); + regmap_write(dphy->regs, SUN6I_DPHY_ANA2_REG, 0); + regmap_write(dphy->regs, SUN6I_DPHY_ANA3_REG, 0); + regmap_write(dphy->regs, SUN6I_DPHY_ANA4_REG, 0); return 0; } @@ -234,6 +389,7 @@ static int sun6i_dphy_exit(struct phy *phy) static const struct phy_ops sun6i_dphy_ops = { + .set_mode = sun6i_dphy_set_mode, .configure = sun6i_dphy_configure, .power_on = sun6i_dphy_power_on, .power_off = sun6i_dphy_power_off, -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:24 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:24 +0100 Subject: [PATCH v2 04/19] media: sun6i-csi: Use common V4L2 format info for storage bpp In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-5-paul.kocialkowski@bootlin.com> V4L2 has a common helper which can be used for calculating the number of stored bits per pixels of a given (stored) image format. Use the helper-returned structure instead of our own switch/case list. Note that a few formats are not in that list so we keep them as special cases. The custom switch/case was also wrong concerning 10/12-bit Bayer formats, which are aligned to 16 bits in memory. Using the common helper fixes it. Fixes: 5cc7522d8965 ("media: sun6i: Add support for Allwinner CSI V3s") Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 55 +++++++------------ 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index c626821aaedb..092445f04c60 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -86,53 +86,38 @@ void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr); */ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable); -/* get bpp form v4l2 pixformat */ +/* get memory storage bpp from v4l2 pixformat */ static inline int sun6i_csi_get_bpp(unsigned int pixformat) { + const struct v4l2_format_info *info; + unsigned int i; + int bpp = 0; + + /* Handle special cases unknown to V4L2 format info first. */ switch (pixformat) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: case V4L2_PIX_FMT_JPEG: return 8; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - return 10; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: case V4L2_PIX_FMT_HM12: - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YVU420: return 12; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - case V4L2_PIX_FMT_UYVY: - case V4L2_PIX_FMT_VYUY: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: return 16; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_BGR24: - return 24; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_BGR32: - return 32; - default: + } + + info = v4l2_format_info(pixformat); + if (!info) { WARN(1, "Unsupported pixformat: 0x%x\n", pixformat); - break; + return 0; + } + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + + /* We return bits per pixel while V4L2 format info is bytes. */ + bpp += 8 * info->bpp[i] / hdiv / vdiv; } - return 0; + return bpp; } #endif /* __SUN6I_CSI_H__ */ -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:25 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:25 +0100 Subject: [PATCH v2 05/19] media: sun6i-csi: Only configure the interface data width for parallel In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-6-paul.kocialkowski@bootlin.com> Bits related to the interface data width are only applicable to the parallel interface and are irrelevant when the CSI controller is taking input from the MIPI CSI-2 controller. In prevision of adding support for this case, set these bits conditionally so there is no ambiguity. The conditional block is moved around before the interlaced conditional block for nicer code symmetry (conditional blocks first) while at it. Co-developed-by: K?vin L'h?pital Signed-off-by: K?vin L'h?pital Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 531a4cccd14a..f1150de94e98 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -378,8 +378,13 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) unsigned char bus_width; u32 flags; u32 cfg; + bool input_parallel = false; bool input_interlaced = false; + if (endpoint->bus_type == V4L2_MBUS_PARALLEL || + endpoint->bus_type == V4L2_MBUS_BT656) + input_parallel = true; + if (csi->config.field == V4L2_FIELD_INTERLACED || csi->config.field == V4L2_FIELD_INTERLACED_TB || csi->config.field == V4L2_FIELD_INTERLACED_BT) @@ -395,6 +400,26 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK | CSI_IF_CFG_SRC_TYPE_MASK); + if (input_parallel) { + switch (bus_width) { + case 8: + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT; + break; + case 10: + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT; + break; + case 12: + cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT; + break; + case 16: /* No need to configure DATA_WIDTH for 16bit */ + break; + default: + dev_warn(sdev->dev, "Unsupported bus width: %u\n", + bus_width); + break; + } + } + if (input_interlaced) cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED; else @@ -440,23 +465,6 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) break; } - switch (bus_width) { - case 8: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT; - break; - case 10: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT; - break; - case 12: - cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT; - break; - case 16: /* No need to configure DATA_WIDTH for 16bit */ - break; - default: - dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width); - break; - } - regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg); } -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:26 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:26 +0100 Subject: [PATCH v2 06/19] dt-bindings: media: sun6i-a31-csi: Add MIPI CSI-2 input port In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-7-paul.kocialkowski@bootlin.com> The A31 CSI controller supports two distinct input interfaces: parallel and an external MIPI CSI-2 bridge. The parallel interface is often connected to a set of hardware pins while the MIPI CSI-2 bridge is an internal FIFO-ish link. As a result, these two inputs are distinguished as two different ports. Note that only one of the two may be present on a controller instance. For example, the V3s has one controller dedicated to MIPI-CSI2 and one dedicated to parallel. Update the binding with an explicit ports node that holds two distinct port nodes: one for parallel input and one for MIPI CSI-2. This is backward-compatible with the single-port approach that was previously taken for representing the parallel interface port, which stays enumerated as fwnode port 0. However, it is now marked as deprecated and the multi-port approach should be preferred. Note that additional ports may be added in the future, especially to support feeding the CSI controller's output to the ISP. Signed-off-by: Paul Kocialkowski --- .../media/allwinner,sun6i-a31-csi.yaml | 86 ++++++++++++++++--- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml index 1fd9b5532a21..3bcee2d44f3c 100644 --- a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml @@ -43,6 +43,7 @@ properties: # See ./video-interfaces.txt for details port: type: object + deprecated: true properties: endpoint: @@ -67,6 +68,59 @@ properties: additionalProperties: false + ports: + type: object + + properties: + port at 0: + type: object + description: Parallel input port, connect to a parallel sensor + + properties: + reg: + const: 0 + + endpoint: + type: object + + properties: + remote-endpoint: true + + bus-width: + enum: [ 8, 10, 12, 16 ] + + pclk-sample: true + hsync-active: true + vsync-active: true + + required: + - bus-width + - remote-endpoint + + required: + - endpoint + + additionalProperties: false + + port at 1: + type: object + description: MIPI CSI-2 bridge input port + + properties: + reg: + const: 1 + + endpoint: + type: object + + properties: + remote-endpoint: true + + required: + - remote-endpoint + + additionalProperties: false + required: - compatible - reg @@ -95,19 +149,25 @@ examples: "ram"; resets = <&ccu RST_BUS_CSI>; - port { - /* Parallel bus endpoint */ - csi1_ep: endpoint { - remote-endpoint = <&adv7611_ep>; - bus-width = <16>; - - /* - * If hsync-active/vsync-active are missing, - * embedded BT.656 sync is used. - */ - hsync-active = <0>; /* Active low */ - vsync-active = <0>; /* Active low */ - pclk-sample = <1>; /* Rising */ + ports { + #address-cells = <1>; + #size-cells = <0>; + + port at 0 { + reg = <0>; + /* Parallel bus endpoint */ + csi1_ep: endpoint { + remote-endpoint = <&adv7611_ep>; + bus-width = <16>; + + /* + * If hsync-active/vsync-active are missing, + * embedded BT.656 sync is used. + */ + hsync-active = <0>; /* Active low */ + vsync-active = <0>; /* Active low */ + pclk-sample = <1>; /* Rising */ + }; }; }; }; -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:27 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:27 +0100 Subject: [PATCH v2 07/19] media: sun6i-csi: Add support for MIPI CSI-2 bridge input In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-8-paul.kocialkowski@bootlin.com> The A31 CSI controller supports a MIPI CSI-2 bridge input, which has its own dedicated port in the fwnode graph. Support for this input is added with this change: - two pads are defined for the media entity instead of one and only one needs to be connected at a time; - the pads currently match the fwnode graph representation; - links are created between our pads and the subdevs for each interface and are no longer immutable so that userspace can select which interface to use in case both are bound to a subdev; - fwnode endpoints are parsed and stored for each interface; - the active subdev (and fwnode endpoint) is retrieved when validating the media link at stream on time and cleared at stream off; - an error is raised if both links are active at the same time; - the MIPI interface bit is set if the MIPI CSI-2 bridge endpoint is active. In the future, the media entity representation might evolve to: - distinguish the internal parallel bridge and data formatter; - represent each of the 4 internal channels that can exist between the parallel bridge (for BT656 time-multiplex) and MIPI CSI-2 (internal channels can be mapped to virtual channels); - connect the controller's output to the ISP instead of its DMA engine. Finally note that the MIPI CSI-2 bridges should not be linked in the fwnode graph unless they have a sensor subdev attached. Signed-off-by: Paul Kocialkowski --- .../platform/sunxi/sun6i-csi/sun6i_csi.c | 123 ++++++++++++++---- .../platform/sunxi/sun6i-csi/sun6i_csi.h | 3 - .../platform/sunxi/sun6i-csi/sun6i_video.c | 53 ++++---- .../platform/sunxi/sun6i-csi/sun6i_video.h | 7 +- 4 files changed, 135 insertions(+), 51 deletions(-) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index f1150de94e98..481181038e1e 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -52,15 +52,16 @@ bool sun6i_csi_is_format_supported(struct sun6i_csi *csi, u32 pixformat, u32 mbus_code) { struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi); + struct v4l2_fwnode_endpoint *endpoint = sdev->csi.video.source_endpoint; /* * Some video receivers have the ability to be compatible with * 8bit and 16bit bus width. * Identify the media bus format from device tree. */ - if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL - || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656) - && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) { + if ((endpoint->bus_type == V4L2_MBUS_PARALLEL + || endpoint->bus_type == V4L2_MBUS_BT656) + && endpoint->bus.parallel.bus_width == 16) { switch (pixformat) { case V4L2_PIX_FMT_HM12: case V4L2_PIX_FMT_NV12: @@ -373,7 +374,7 @@ static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev, static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) { - struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep; + struct v4l2_fwnode_endpoint *endpoint = sdev->csi.video.source_endpoint; struct sun6i_csi *csi = &sdev->csi; unsigned char bus_width; u32 flags; @@ -459,6 +460,9 @@ static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev) if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE; break; + case V4L2_MBUS_CSI2_DPHY: + cfg |= CSI_IF_CFG_MIPI_IF_MIPI; + break; default: dev_warn(sdev->dev, "Unsupported bus type: %d\n", endpoint->bus_type); @@ -636,11 +640,11 @@ void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable) * Media Controller and V4L2 */ static int sun6i_csi_link_entity(struct sun6i_csi *csi, + struct media_pad *sink_pad, struct media_entity *entity, - struct fwnode_handle *fwnode) + struct fwnode_handle *fwnode, bool enabled) { struct media_entity *sink; - struct media_pad *sink_pad; int src_pad_index; int ret; @@ -654,14 +658,12 @@ static int sun6i_csi_link_entity(struct sun6i_csi *csi, src_pad_index = ret; sink = &csi->video.vdev.entity; - sink_pad = &csi->video.pad; dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n", entity->name, src_pad_index, sink->name, sink_pad->index); ret = media_create_pad_link(entity, src_pad_index, sink, sink_pad->index, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); + enabled ? MEDIA_LNK_FL_ENABLED : 0); if (ret < 0) { dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n", entity->name, src_pad_index, @@ -676,19 +678,67 @@ static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier) { struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi, notifier); + struct sun6i_video *video = &csi->video; struct v4l2_device *v4l2_dev = &csi->v4l2_dev; - struct v4l2_subdev *sd; + struct v4l2_subdev *parallel_sd = NULL; + struct v4l2_subdev *mipi_csi2_bridge_sd = NULL; + struct fwnode_handle *handle = NULL; int ret; dev_dbg(csi->dev, "notify complete, all subdevs registered\n"); - sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list); - if (!sd) - return -EINVAL; + /* Find the subdevs that match our fwnode ports. */ + while (1) { + struct v4l2_fwnode_link link; + struct v4l2_subdev *sd; - ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode); - if (ret < 0) - return ret; + handle = fwnode_graph_get_next_endpoint(dev_fwnode(csi->dev), + handle); + if (!handle) + break; + + ret = v4l2_fwnode_parse_link(handle, &link); + if (ret) + break; + + list_for_each_entry(sd, &v4l2_dev->subdevs, list) { + if (!sd->fwnode || link.remote_node != sd->fwnode) + continue; + + switch (link.local_port) { + case 0: + parallel_sd = sd; + break; + case 1: + mipi_csi2_bridge_sd = sd; + break; + } + } + + v4l2_fwnode_put_link(&link); + } + + if (parallel_sd) { + dev_dbg(csi->dev, "linking parallel interface subdev\n"); + + ret = sun6i_csi_link_entity(csi, &video->pads[0], + ¶llel_sd->entity, + parallel_sd->fwnode, true); + if (ret < 0) + return ret; + } + + if (mipi_csi2_bridge_sd) { + dev_dbg(csi->dev, "linking MIPI CSI-2 bridge subdev\n"); + + /* Mark the link as disabled if a parallel subdev is there. */ + ret = sun6i_csi_link_entity(csi, &video->pads[1], + &mipi_csi2_bridge_sd->entity, + mipi_csi2_bridge_sd->fwnode, + parallel_sd ? false : true); + if (ret < 0) + return ret; + } ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev); if (ret < 0) @@ -706,21 +756,44 @@ static int sun6i_csi_fwnode_parse(struct device *dev, struct v4l2_async_subdev *asd) { struct sun6i_csi *csi = dev_get_drvdata(dev); + struct sun6i_video *video = &csi->video; + struct v4l2_fwnode_endpoint *endpoint = NULL; + + switch (vep->base.port) { + case 0: + endpoint = &video->parallel_endpoint; - if (vep->base.port || vep->base.id) { - dev_warn(dev, "Only support a single port with one endpoint\n"); + switch (vep->bus_type) { + case V4L2_MBUS_PARALLEL: + case V4L2_MBUS_BT656: + break; + default: + dev_err(dev, "Unsupported media bus type\n"); + return -ENOTCONN; + } + break; + case 1: + endpoint = &video->mipi_csi2_bridge_endpoint; + break; + default: + dev_warn(dev, "Unsupported port at index %u\n", vep->base.port); return -ENOTCONN; } - switch (vep->bus_type) { - case V4L2_MBUS_PARALLEL: - case V4L2_MBUS_BT656: - csi->v4l2_ep = *vep; - return 0; - default: - dev_err(dev, "Unsupported media bus type\n"); + if (vep->base.id) { + dev_warn(dev, "Unsupported endpoint at index %u for port %u\n", + vep->base.id, vep->base.port); return -ENOTCONN; } + + *endpoint = *vep; + + if (vep->base.port == 1) { + /* Set this for our local convenience. */ + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + } + + return 0; } static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi) diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h index 092445f04c60..d7b15452ab3a 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.h @@ -40,9 +40,6 @@ struct sun6i_csi { struct v4l2_async_notifier notifier; - /* video port settings */ - struct v4l2_fwnode_endpoint v4l2_ep; - struct sun6i_csi_config config; struct sun6i_video video; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index b55de9ab64d8..5bb7c013f6bb 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -72,22 +72,6 @@ static bool is_pixformat_valid(unsigned int pixformat) return false; } -static struct v4l2_subdev * -sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad) -{ - struct media_pad *remote; - - remote = media_entity_remote_pad(&video->pad); - - if (!remote || !is_media_entity_v4l2_subdev(remote->entity)) - return NULL; - - if (pad) - *pad = remote->index; - - return media_entity_to_v4l2_subdev(remote->entity); -} - static int sun6i_video_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, @@ -150,7 +134,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) goto stop_media_pipeline; } - subdev = sun6i_video_remote_subdev(video, NULL); + subdev = video->source_subdev; if (!subdev) goto stop_media_pipeline; @@ -206,6 +190,7 @@ static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count) sun6i_csi_set_stream(video->csi, false); stop_media_pipeline: media_pipeline_stop(&video->vdev.entity); + video->source_subdev = NULL; clear_dma_queue: spin_lock_irqsave(&video->dma_queue_lock, flags); list_for_each_entry(buf, &video->dma_queue, list) @@ -223,13 +208,16 @@ static void sun6i_video_stop_streaming(struct vb2_queue *vq) unsigned long flags; struct sun6i_csi_buffer *buf; - subdev = sun6i_video_remote_subdev(video, NULL); + subdev = video->source_subdev; if (subdev) v4l2_subdev_call(subdev, video, s_stream, 0); sun6i_csi_set_stream(video->csi, false); - media_pipeline_stop(&video->vdev.entity); + if (subdev) + media_pipeline_stop(&video->vdev.entity); + + video->source_subdev = NULL; /* Release all active buffers */ spin_lock_irqsave(&video->dma_queue_lock, flags); @@ -550,16 +538,36 @@ static int sun6i_video_link_validate(struct media_link *link) struct video_device, entity); struct sun6i_video *video = video_get_drvdata(vdev); struct v4l2_subdev_format source_fmt; + struct v4l2_subdev *subdev; int ret; video->mbus_code = 0; - if (!media_entity_remote_pad(link->sink->entity->pads)) { + if (!link->source) { dev_info(video->csi->dev, "video node %s pad not connected\n", vdev->name); return -ENOLINK; } + if (!is_media_entity_v4l2_subdev(link->source->entity)) + return -ENODEV; + + subdev = media_entity_to_v4l2_subdev(link->source->entity); + + if (video->source_subdev) { + dev_err(video->csi->dev, + "unable to connect both parallel and MIPI CSI-2 bridge interfaces\n"); + return -ENOLINK; + } + + if (link->sink == &video->pads[0]) { + video->source_endpoint = &video->parallel_endpoint; + video->source_subdev = subdev; + } else if (link->sink == &video->pads[1]) { + video->source_endpoint = &video->mipi_csi2_bridge_endpoint; + video->source_subdev = subdev; + } + ret = sun6i_video_link_validate_get_format(link->source, &source_fmt); if (ret < 0) return ret; @@ -603,9 +611,10 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, video->csi = csi; /* Initialize the media entity... */ - video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT; + video->pads[0].flags = MEDIA_PAD_FL_SINK; + video->pads[1].flags = MEDIA_PAD_FL_SINK; vdev->entity.ops = &sun6i_video_media_ops; - ret = media_entity_pads_init(&vdev->entity, 1, &video->pad); + ret = media_entity_pads_init(&vdev->entity, 2, video->pads); if (ret < 0) return ret; diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h index b9cd919c24ac..30d56d98d5e9 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.h @@ -15,11 +15,16 @@ struct sun6i_csi; struct sun6i_video { struct video_device vdev; - struct media_pad pad; + struct media_pad pads[2]; struct sun6i_csi *csi; struct mutex lock; + struct v4l2_fwnode_endpoint parallel_endpoint; + struct v4l2_fwnode_endpoint mipi_csi2_bridge_endpoint; + struct v4l2_fwnode_endpoint *source_endpoint; + struct v4l2_subdev *source_subdev; + struct vb2_queue vb2_vidq; spinlock_t dma_queue_lock; struct list_head dma_queue; -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:29 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:29 +0100 Subject: [PATCH v2 09/19] ARM: dts: sunxi: h3/h5: Add CSI controller port for parallel input In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-10-paul.kocialkowski@bootlin.com> Since the CSI controller binding is getting a bit more complex due to the addition of MIPI CSI-2 bridge support, make the ports node explicit with the parallel port. This way, it's clear that the controller only supports parallel interface input and there's no confusion about the port number. Signed-off-by: Paul Kocialkowski --- arch/arm/boot/dts/sunxi-h3-h5.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/sunxi-h3-h5.dtsi b/arch/arm/boot/dts/sunxi-h3-h5.dtsi index 9be13378d4df..02b698cace6a 100644 --- a/arch/arm/boot/dts/sunxi-h3-h5.dtsi +++ b/arch/arm/boot/dts/sunxi-h3-h5.dtsi @@ -803,6 +803,15 @@ csi: camera at 1cb0000 { pinctrl-names = "default"; pinctrl-0 = <&csi_pins>; status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi_in_parallel: port at 0 { + reg = <0>; + }; + }; }; hdmi: hdmi at 1ee0000 { -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:28 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:28 +0100 Subject: [PATCH v2 08/19] ARM: dts: sun8i: a83t: Add CSI controller ports In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-9-paul.kocialkowski@bootlin.com> Since the CSI controller binding is getting a bit more complex due to the addition of MIPI CSI-2 bridge support, make the ports node explicit with the parallel and MIPI CSI-2 bridge ports. This way, it's clear that the controller supports both parallel and MIPI CSI-2 interface inputs and there's no confusion about their port number. Signed-off-by: Paul Kocialkowski --- arch/arm/boot/dts/sun8i-a83t.dtsi | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index c010b27fdb6a..3ce030f7e05d 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -1062,7 +1062,17 @@ csi: camera at 1cb0000 { resets = <&ccu RST_BUS_CSI>; status = "disabled"; - csi_in: port { + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi_in_parallel: port at 0 { + reg = <0>; + }; + + csi_in_mipi_csi2_bridge: port at 1 { + reg = <1>; + }; }; }; -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:30 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:30 +0100 Subject: [PATCH v2 10/19] ARM: dts: sun8i: v3s: Add CSI1 controller port for parallel input In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-11-paul.kocialkowski@bootlin.com> Since the CSI controller binding is getting a bit more complex due to the addition of MIPI CSI-2 bridge support, make the ports node explicit with the parallel port. This way, it's clear that the controller only supports parallel interface input and there's no confusion about the port number. Signed-off-by: Paul Kocialkowski --- arch/arm/boot/dts/sun8i-v3s.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index 7b2d684aeb97..7926c8b2ac5e 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -540,6 +540,15 @@ csi1: camera at 1cb4000 { clock-names = "bus", "mod", "ram"; resets = <&ccu RST_BUS_CSI>; status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi1_in_parallel: port at 0 { + reg = <0>; + }; + }; }; gic: interrupt-controller at 1c81000 { -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:31 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:31 +0100 Subject: [PATCH v2 11/19] arm64: dts: allwinner: a64: Add CSI controller port for parallel input In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-12-paul.kocialkowski@bootlin.com> Since the CSI controller binding is getting a bit more complex due to the addition of MIPI CSI-2 bridge support, make the ports node explicit with the parallel port. This way, it's clear that the controller only supports parallel interface input and there's no confusion about the port number. Signed-off-by: Paul Kocialkowski --- arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi index 51cc30e84e26..1e1f0d2097d5 100644 --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi @@ -1109,6 +1109,15 @@ csi: csi at 1cb0000 { pinctrl-names = "default"; pinctrl-0 = <&csi_pins>; status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + csi_in_parallel: port at 0 { + reg = <0>; + }; + }; }; dsi: dsi at 1ca0000 { -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:32 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:32 +0100 Subject: [PATCH v2 12/19] dt-bindings: media: Add A31 MIPI CSI-2 bindings documentation In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-13-paul.kocialkowski@bootlin.com> This introduces YAML bindings documentation for the A31 MIPI CSI-2 controller. Signed-off-by: Paul Kocialkowski --- .../media/allwinner,sun6i-a31-mipi-csi2.yaml | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml new file mode 100644 index 000000000000..917cd09d6fda --- /dev/null +++ b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml @@ -0,0 +1,151 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/allwinner,sun6i-a31-mipi-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A31 MIPI CSI-2 Device Tree Bindings + +maintainers: + - Paul Kocialkowski + +properties: + compatible: + oneOf: + - const: allwinner,sun6i-a31-mipi-csi2 + - items: + - const: allwinner,sun8i-v3s-mipi-csi2 + - const: allwinner,sun6i-a31-mipi-csi2 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + + clock-names: + items: + - const: bus + - const: mod + + phys: + items: + - description: MIPI D-PHY + + phy-names: + items: + - const: dphy + + resets: + maxItems: 1 + + # See ./video-interfaces.txt for details + ports: + type: object + + properties: + port at 0: + type: object + description: Input port, connect to a MIPI CSI-2 sensor + + properties: + reg: + const: 0 + + endpoint: + type: object + + properties: + remote-endpoint: true + + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + - remote-endpoint + + required: + - endpoint + + additionalProperties: false + + port at 1: + type: object + description: Output port, connect to a CSI controller + + properties: + reg: + const: 1 + + endpoint: + type: object + + properties: + remote-endpoint: true + + required: + - endpoint + + additionalProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + + mipi_csi2: csi at 1cb1000 { + compatible = "allwinner,sun8i-v3s-mipi-csi2", + "allwinner,sun6i-a31-mipi-csi2"; + reg = <0x01cb1000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_CSI1_SCLK>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_CSI>; + + phys = <&dphy>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mipi_csi2_in: port at 0 { + reg = <0>; + + mipi_csi2_in_ov5648: endpoint { + data-lanes = <1 2 3 4>; + + remote-endpoint = <&ov5648_out_mipi_csi2>; + }; + }; + + mipi_csi2_out: port at 1 { + reg = <1>; + + mipi_csi2_out_csi0: endpoint { + remote-endpoint = <&csi0_in_mipi_csi2>; + }; + }; + }; + }; + +... -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:33 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:33 +0100 Subject: [PATCH v2 13/19] media: sunxi: Add support for the A31 MIPI CSI-2 controller In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-14-paul.kocialkowski@bootlin.com> The A31 MIPI CSI-2 controller is a dedicated MIPI CSI-2 bridge found on Allwinner SoCs such as the A31 and V3/V3s. It is a standalone block, connected to the CSI controller on one side and to the MIPI D-PHY block on the other. It has a dedicated address space, interrupt line and clock. It is represented as a V4L2 subdev to the CSI controller and takes a MIPI CSI-2 sensor as its own subdev, all using the fwnode graph and media controller API. Only 8-bit and 10-bit Bayer formats are currently supported. While up to 4 internal channels to the CSI controller exist, only one is currently supported by this implementation. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/Kconfig | 1 + drivers/media/platform/sunxi/Makefile | 1 + .../platform/sunxi/sun6i-mipi-csi2/Kconfig | 12 + .../platform/sunxi/sun6i-mipi-csi2/Makefile | 4 + .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c | 591 ++++++++++++++++++ .../sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h | 117 ++++ 6 files changed, 726 insertions(+) create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c create mode 100644 drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig index 7151cc249afa..9684e07454ad 100644 --- a/drivers/media/platform/sunxi/Kconfig +++ b/drivers/media/platform/sunxi/Kconfig @@ -2,3 +2,4 @@ source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" +source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index fc537c9f5ca9..887a7cae8fca 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -2,5 +2,6 @@ obj-y += sun4i-csi/ obj-y += sun6i-csi/ +obj-y += sun6i-mipi-csi2/ obj-y += sun8i-di/ obj-y += sun8i-rotate/ diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig new file mode 100644 index 000000000000..3260591ed5c0 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN6I_MIPI_CSI2 + tristate "Allwinner A31 MIPI CSI-2 Controller Driver" + depends on VIDEO_V4L2 && COMMON_CLK + depends on ARCH_SUNXI || COMPILE_TEST + select PHY_SUN6I_MIPI_DPHY + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select REGMAP_MMIO + select V4L2_FWNODE + help + Support for the Allwinner A31 MIPI CSI-2 Controller. diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile new file mode 100644 index 000000000000..14e4e03818b5 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun6i-mipi-csi2-y += sun6i_mipi_csi2.o + +obj-$(CONFIG_VIDEO_SUN6I_MIPI_CSI2) += sun6i-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c new file mode 100644 index 000000000000..a6567ef82fb4 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sun6i_mipi_csi2.h" + +#define MODULE_NAME "sun6i-mipi-csi2" + +static const u32 sun6i_mipi_csi2_mbus_codes[] = { + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, +}; + +/* Video */ + +static int sun6i_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun6i_mipi_csi2_video *video = + sun6i_mipi_csi2_subdev_video(subdev); + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); + struct v4l2_subdev *remote_subdev = video->remote_subdev; + struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + &video->endpoint.bus.mipi_csi2; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct regmap *regmap = cdev->regmap; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count; + unsigned int bpp; + unsigned long pixel_rate; + u8 data_type = 0; + u32 version = 0; + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ + int ret = 0; + + if (!remote_subdev) + return -ENODEV; + + if (!on) { + v4l2_subdev_call(remote_subdev, video, s_stream, 0); + goto disable; + } + + switch (video->mbus_format.code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + data_type = MIPI_CSI2_DATA_TYPE_RAW8; + bpp = 8; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + data_type = MIPI_CSI2_DATA_TYPE_RAW10; + bpp = 10; + break; + default: + return -EINVAL; + } + + /* Sensor pixel rate */ + + ctrl = v4l2_ctrl_find(remote_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(cdev->dev, + "%s: no MIPI CSI-2 pixel rate from the sensor\n", + __func__); + return -ENODEV; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(cdev->dev, + "%s: zero MIPI CSI-2 pixel rate from the sensor\n", + __func__); + return -ENODEV; + } + + /* Power management */ + + ret = pm_runtime_get_sync(cdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(cdev->dev); + return ret; + } + + /* D-PHY configuration */ + + lanes_count = bus_mipi_csi2->num_data_lanes; + phy_mipi_dphy_get_default_config(pixel_rate, bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(cdev->dev, "A31 MIPI CSI-2 config:\n"); + dev_dbg(cdev->dev, "%ld pixels/s, %u bits/pixel, %lu Hz clock\n", + pixel_rate, bpp, dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(cdev->dphy); + if (ret) { + dev_err(cdev->dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, + PHY_MIPI_DPHY_SUBMODE_RX); + if (ret) { + dev_err(cdev->dev, "failed to set MIPI D-PHY mode\n"); + goto error_pm; + } + + ret = phy_configure(cdev->dphy, &dphy_opts); + if (ret) { + dev_err(cdev->dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_power_on(cdev->dphy); + if (ret) { + dev_err(cdev->dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* MIPI CSI-2 controller setup */ + + /* + * The enable flow in the Allwinner BSP is a bit different: the enable + * and reset bits are set together before starting the CSI controller. + * + * In mainline we enable the CSI controller first (due to subdev logic). + * One reliable way to make this work is to deassert reset, configure + * registers and enable the controller when everything's ready. + * + * However, setting the version enable bit and removing it afterwards + * appears necessary for capture to work reliably, while replacing it + * with a delay doesn't do the trick. + */ + regmap_write(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_RESET_N | + SUN6I_MIPI_CSI2_CTL_VERSION_EN | + SUN6I_MIPI_CSI2_CTL_UNPK_EN); + + regmap_read(regmap, SUN6I_MIPI_CSI2_VERSION_REG, &version); + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_VERSION_EN, 0); + + dev_dbg(cdev->dev, "A31 MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN6I_MIPI_CSI2_CFG_REG, + SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(1) | + SUN6I_MIPI_CSI2_CFG_LANE_COUNT(lanes_count)); + + /* + * Our MIPI CSI-2 controller has internal channels that can be + * configured to match a specific MIPI CSI-2 virtual channel and/or + * a specific data type. Each internal channel can be piped to an + * internal channel of the CSI controller. + * + * We set virtual channel numbers to all channels to make sure that + * virtual channel 0 goes to CSI channel 0 only. + */ + regmap_write(regmap, SUN6I_MIPI_CSI2_VCDT_RX_REG, + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(3, 3) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(2, 2) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(1, 1) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(0, 0) | + SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(0, data_type)); + + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, SUN6I_MIPI_CSI2_CTL_EN); + + ret = v4l2_subdev_call(remote_subdev, video, s_stream, 1); + if (ret) + goto disable; + + return 0; + +disable: + regmap_update_bits(regmap, SUN6I_MIPI_CSI2_CTL_REG, + SUN6I_MIPI_CSI2_CTL_EN, 0); + + phy_power_off(cdev->dphy); + +error_pm: + pm_runtime_put(cdev->dev); + + return ret; +} + +static const struct v4l2_subdev_video_ops sun6i_mipi_csi2_subdev_video_ops = { + .s_stream = sun6i_mipi_csi2_s_stream, +}; + +/* Pad */ + +static int +sun6i_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun6i_mipi_csi2_mbus_codes)) + return -EINVAL; + + code_enum->code = sun6i_mipi_csi2_mbus_codes[code_enum->index]; + + return 0; +} + +static int sun6i_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_video *video = + sun6i_mipi_csi2_subdev_video(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, config, + format->pad); + else + *mbus_format = video->mbus_format; + + return 0; +} + +static int sun6i_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_format *format) +{ + struct sun6i_mipi_csi2_video *video = + sun6i_mipi_csi2_subdev_video(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, config, format->pad) = + *mbus_format; + else + video->mbus_format = *mbus_format; + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun6i_mipi_csi2_subdev_pad_ops = { + .enum_mbus_code = sun6i_mipi_csi2_enum_mbus_code, + .get_fmt = sun6i_mipi_csi2_get_fmt, + .set_fmt = sun6i_mipi_csi2_set_fmt, +}; + +/* Subdev */ + +static const struct v4l2_subdev_ops sun6i_mipi_csi2_subdev_ops = { + .video = &sun6i_mipi_csi2_subdev_video_ops, + .pad = &sun6i_mipi_csi2_subdev_pad_ops, +}; + +/* Notifier */ + +static int +sun6i_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *remote_subdev_async) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun6i_mipi_csi2_video *video = + sun6i_mipi_csi2_subdev_video(subdev); + struct sun6i_mipi_csi2_dev *cdev = sun6i_mipi_csi2_video_dev(video); + int source_pad; + int ret; + + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, + remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) + return source_pad; + + ret = media_create_pad_link(&remote_subdev->entity, source_pad, + &subdev->entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", + remote_subdev->entity.name, source_pad, + subdev->entity.name, 0); + return ret; + } + + video->remote_subdev = remote_subdev; + + return 0; +} + +static const +struct v4l2_async_notifier_operations sun6i_mipi_csi2_notifier_ops = { + .bound = sun6i_mipi_csi2_notifier_bound, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun6i_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* Base Driver */ + +static int __maybe_unused sun6i_mipi_csi2_suspend(struct device *dev) +{ + struct sun6i_mipi_csi2_dev *cdev = dev_get_drvdata(dev); + + clk_disable_unprepare(cdev->clk_mod); + clk_disable_unprepare(cdev->clk_bus); + reset_control_assert(cdev->reset); + + return 0; +} + +static int __maybe_unused sun6i_mipi_csi2_resume(struct device *dev) +{ + struct sun6i_mipi_csi2_dev *cdev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(cdev->reset); + if (ret) { + dev_err(cdev->dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(cdev->clk_bus); + if (ret) { + dev_err(cdev->dev, "failed to enable bus clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(cdev->clk_mod); + if (ret) { + dev_err(cdev->dev, "failed to enable module clock\n"); + goto error_clk_bus; + } + + return 0; + +error_clk_bus: + clk_disable_unprepare(cdev->clk_bus); + +error_reset: + reset_control_assert(cdev->reset); + + return ret; +} + +static int sun6i_mipi_csi2_v4l2_setup(struct sun6i_mipi_csi2_dev *cdev) +{ + struct sun6i_mipi_csi2_video *video = &cdev->video; + struct v4l2_subdev *subdev = &video->subdev; + struct v4l2_async_notifier *notifier = &video->notifier; + struct fwnode_handle *handle; + struct v4l2_fwnode_endpoint *endpoint; + struct v4l2_async_subdev *subdev_async; + int ret; + + /* Subdev */ + + v4l2_subdev_init(subdev, &sun6i_mipi_csi2_subdev_ops); + subdev->dev = cdev->dev; + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strscpy(subdev->name, MODULE_NAME, sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, cdev); + + /* Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun6i_mipi_csi2_entity_ops; + + /* Pads */ + + video->pads[0].flags = MEDIA_PAD_FL_SINK; + video->pads[1].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, 2, video->pads); + if (ret) + return ret; + + /* Endpoint */ + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(cdev->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) { + ret = -ENODEV; + goto error_media_entity; + } + + endpoint = &video->endpoint; + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + fwnode_handle_put(handle); + if (ret) + goto error_media_entity; + + /* Notifier */ + + v4l2_async_notifier_init(notifier); + + subdev_async = &video->subdev_async; + ret = v4l2_async_notifier_add_fwnode_remote_subdev(notifier, handle, + subdev_async); + if (ret) + goto error_media_entity; + + video->notifier.ops = &sun6i_mipi_csi2_notifier_ops; + + ret = v4l2_async_subdev_notifier_register(subdev, notifier); + if (ret < 0) + goto error_notifier; + + /* Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_notifier_registered; + + /* Runtime PM */ + + pm_runtime_enable(cdev->dev); + pm_runtime_set_suspended(cdev->dev); + + return 0; + +error_notifier_registered: + v4l2_async_notifier_unregister(notifier); +error_notifier: + v4l2_async_notifier_cleanup(notifier); +error_media_entity: + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static int sun6i_mipi_csi2_v4l2_teardown(struct sun6i_mipi_csi2_dev *cdev) +{ + struct sun6i_mipi_csi2_video *video = &cdev->video; + struct v4l2_subdev *subdev = &video->subdev; + struct v4l2_async_notifier *notifier = &video->notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_notifier_unregister(notifier); + v4l2_async_notifier_cleanup(notifier); + media_entity_cleanup(&subdev->entity); + v4l2_device_unregister_subdev(subdev); + + return 0; +} + +static const struct regmap_config sun6i_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x400, +}; + +static int sun6i_mipi_csi2_probe(struct platform_device *pdev) +{ + struct sun6i_mipi_csi2_dev *cdev; + struct resource *res; + void __iomem *io_base; + int ret; + + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + cdev->regmap = devm_regmap_init_mmio(&pdev->dev, io_base, + &sun6i_mipi_csi2_regmap_config); + if (IS_ERR(cdev->regmap)) { + dev_err(&pdev->dev, "failed to init register map\n"); + return PTR_ERR(cdev->regmap); + } + + cdev->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(cdev->clk_bus)) { + dev_err(&pdev->dev, "failed to acquire bus clock\n"); + return PTR_ERR(cdev->clk_bus); + } + + cdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(cdev->clk_mod)) { + dev_err(&pdev->dev, "failed to acquire mod clock\n"); + return PTR_ERR(cdev->clk_mod); + } + + cdev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(cdev->reset)) { + dev_err(&pdev->dev, "failed to get reset controller\n"); + return PTR_ERR(cdev->reset); + } + + cdev->dphy = devm_phy_get(&pdev->dev, "dphy"); + if (IS_ERR(cdev->dphy)) { + dev_err(&pdev->dev, "failed to get the MIPI D-PHY\n"); + return PTR_ERR(cdev->dphy); + } + + ret = phy_init(cdev->dphy); + if (ret) { + dev_err(&pdev->dev, "failed to initialize the MIPI D-PHY\n"); + return ret; + } + + platform_set_drvdata(pdev, cdev); + + ret = sun6i_mipi_csi2_v4l2_setup(cdev); + if (ret) + return ret; + + return 0; +} + +static int sun6i_mipi_csi2_remove(struct platform_device *pdev) +{ + struct sun6i_mipi_csi2_dev *cdev = platform_get_drvdata(pdev); + + phy_exit(cdev->dphy); + + return sun6i_mipi_csi2_v4l2_teardown(cdev); +} + +static const struct dev_pm_ops sun6i_mipi_csi2_pm_ops = { + SET_RUNTIME_PM_OPS(sun6i_mipi_csi2_suspend, sun6i_mipi_csi2_resume, + NULL) +}; + +static const struct of_device_id sun6i_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun6i-a31-mipi-csi2" }, + { .compatible = "allwinner,sun8i-v3s-mipi-csi2", }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match); + +static struct platform_driver sun6i_mipi_csi2_platform_driver = { + .probe = sun6i_mipi_csi2_probe, + .remove = sun6i_mipi_csi2_remove, + .driver = { + .name = MODULE_NAME, + .of_match_table = of_match_ptr(sun6i_mipi_csi2_of_match), + .pm = &sun6i_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun6i_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A31 MIPI CSI-2 Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h new file mode 100644 index 000000000000..b132ac8873b6 --- /dev/null +++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#ifndef __SUN6I_MIPI_CSI2_H__ +#define __SUN6I_MIPI_CSI2_H__ + +#include +#include +#include +#include +#include + +#define SUN6I_MIPI_CSI2_CTL_REG 0x0 +#define SUN6I_MIPI_CSI2_CTL_RESET_N BIT(31) +#define SUN6I_MIPI_CSI2_CTL_VERSION_EN BIT(30) +#define SUN6I_MIPI_CSI2_CTL_UNPK_EN BIT(1) +#define SUN6I_MIPI_CSI2_CTL_EN BIT(0) +#define SUN6I_MIPI_CSI2_CFG_REG 0x4 +#define SUN6I_MIPI_CSI2_CFG_CHANNEL_MODE(v) ((((v) - 1) << 8) & \ + GENMASK(9, 8)) +#define SUN6I_MIPI_CSI2_CFG_LANE_COUNT(v) (((v) - 1) & GENMASK(1, 0)) +#define SUN6I_MIPI_CSI2_VCDT_RX_REG 0x8 +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN6I_MIPI_CSI2_VCDT_RX_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN6I_MIPI_CSI2_RX_PKT_NUM_REG 0xc + +#define SUN6I_MIPI_CSI2_VERSION_REG 0x3c + +#define SUN6I_MIPI_CSI2_CH_BASE 0x1000 +#define SUN6I_MIPI_CSI2_CH_OFFSET 0x100 + +#define SUN6I_MIPI_CSI2_CH_CFG_REG 0x40 +#define SUN6I_MIPI_CSI2_CH_INT_EN_REG 0x50 +#define SUN6I_MIPI_CSI2_CH_INT_EN_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_EN_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_EN_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_EN_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_EN_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_EN_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_EN_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_INT_PD_REG 0x58 +#define SUN6I_MIPI_CSI2_CH_INT_PD_EOT_ERR BIT(29) +#define SUN6I_MIPI_CSI2_CH_INT_PD_CHKSUM_ERR BIT(28) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_WRN BIT(27) +#define SUN6I_MIPI_CSI2_CH_INT_PD_ECC_ERR BIT(26) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_SYNC_ERR BIT(25) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_SYNC_ERR BIT(24) +#define SUN6I_MIPI_CSI2_CH_INT_PD_EMB_DATA BIT(18) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PF BIT(17) +#define SUN6I_MIPI_CSI2_CH_INT_PD_PH_UPDATE BIT(16) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_START_SYNC BIT(11) +#define SUN6I_MIPI_CSI2_CH_INT_PD_LINE_END_SYNC BIT(10) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_START_SYNC BIT(9) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FRAME_END_SYNC BIT(8) +#define SUN6I_MIPI_CSI2_CH_INT_PD_FIFO_OVER BIT(0) + +#define SUN6I_MIPI_CSI2_CH_DT_TRIGGER_REG 0x60 +#define SUN6I_MIPI_CSI2_CH_CUR_PH_REG 0x70 +#define SUN6I_MIPI_CSI2_CH_ECC_REG 0x74 +#define SUN6I_MIPI_CSI2_CH_CKS_REG 0x78 +#define SUN6I_MIPI_CSI2_CH_FRAME_NUM_REG 0x7c +#define SUN6I_MIPI_CSI2_CH_LINE_NUM_REG 0x80 + +#define SUN6I_MIPI_CSI2_CH_REG(reg, ch) \ + (SUN6I_MIPI_CSI2_CH_BASE + SUN6I_MIPI_CSI2_CH_OFFSET * (ch) + (reg)) + +enum mipi_csi2_data_type { + MIPI_CSI2_DATA_TYPE_RAW8 = 0x2a, + MIPI_CSI2_DATA_TYPE_RAW10 = 0x2b, + MIPI_CSI2_DATA_TYPE_RAW12 = 0x2c, +}; + +struct sun6i_mipi_csi2_video { + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_subdev subdev; + struct media_pad pads[2]; + + struct v4l2_async_subdev subdev_async; + struct v4l2_async_notifier notifier; + + struct v4l2_subdev *remote_subdev; + + struct v4l2_mbus_framefmt mbus_format; +}; + +struct sun6i_mipi_csi2_dev { + struct device *dev; + + struct regmap *regmap; + struct clk *clk_bus; + struct clk *clk_mod; + struct reset_control *reset; + struct phy *dphy; + + struct sun6i_mipi_csi2_video video; +}; + +#define sun6i_mipi_csi2_subdev_video(subdev) \ + container_of(subdev, struct sun6i_mipi_csi2_video, subdev) + +#define sun6i_mipi_csi2_video_dev(video) \ + container_of(video, struct sun6i_mipi_csi2_dev, video) + +#endif /* __SUN6I_MIPI_CSI2_H__ */ -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:34 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:34 +0100 Subject: [PATCH v2 14/19] ARM: dts: sun8i: v3s: Add nodes for MIPI CSI-2 support In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-15-paul.kocialkowski@bootlin.com> MIPI CSI-2 is supported on the V3s with an A31-based MIPI CSI-2 bridge controller. The controller uses a separate D-PHY, which is the same that is otherwise used for MIPI DSI, but used in Rx mode. On the V3s, the CSI0 controller is dedicated to MIPI CSI-2 as it does not have access to any parallel interface pins. Add all the necessary nodes (CSI0, MIPI CSI-2 bridge and D-PHY) to support the MIPI CSI-2 interface. Note that a fwnode graph link is created between CSI0 and MIPI CSI-2 even when no sensor is connected. This will result in a probe failure for the controller as long as no sensor is connected but this is fine since no other interface is available. Signed-off-by: Paul Kocialkowski --- arch/arm/boot/dts/sun8i-v3s.dtsi | 68 ++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-v3s.dtsi b/arch/arm/boot/dts/sun8i-v3s.dtsi index 7926c8b2ac5e..641da6c7bca0 100644 --- a/arch/arm/boot/dts/sun8i-v3s.dtsi +++ b/arch/arm/boot/dts/sun8i-v3s.dtsi @@ -530,6 +530,31 @@ spi0: spi at 1c68000 { #size-cells = <0>; }; + csi0: camera at 1cb0000 { + compatible = "allwinner,sun8i-v3s-csi"; + reg = <0x01cb0000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_CSI1_SCLK>, + <&ccu CLK_DRAM_CSI>; + clock-names = "bus", "mod", "ram"; + resets = <&ccu RST_BUS_CSI>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port at 1 { + reg = <1>; + + csi0_in_mipi_csi2: endpoint { + remote-endpoint = <&mipi_csi2_out_csi0>; + }; + }; + }; + }; + csi1: camera at 1cb4000 { compatible = "allwinner,sun8i-v3s-csi"; reg = <0x01cb4000 0x3000>; @@ -561,5 +586,48 @@ gic: interrupt-controller at 1c81000 { #interrupt-cells = <3>; interrupts = ; }; + + mipi_csi2: csi at 1cb1000 { + compatible = "allwinner,sun8i-v3s-mipi-csi2", + "allwinner,sun6i-a31-mipi-csi2"; + reg = <0x01cb1000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_CSI1_SCLK>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_CSI>; + status = "disabled"; + + phys = <&dphy>; + phy-names = "dphy"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mipi_csi2_in: port at 0 { + reg = <0>; + }; + + mipi_csi2_out: port at 1 { + reg = <1>; + + mipi_csi2_out_csi0: endpoint { + remote-endpoint = <&csi0_in_mipi_csi2>; + }; + }; + }; + }; + + dphy: d-phy at 1cb2000 { + compatible = "allwinner,sun6i-a31-mipi-dphy"; + reg = <0x01cb2000 0x1000>; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_MIPI_CSI>; + clock-names = "bus", "mod"; + resets = <&ccu RST_BUS_CSI>; + status = "disabled"; + #phy-cells = <0>; + }; }; }; -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:35 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:35 +0100 Subject: [PATCH v2 15/19] MAINTAINERS: Add entry for the Allwinner A31 MIPI CSI-2 bridge In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-16-paul.kocialkowski@bootlin.com> Add myself as maintainer of the A31 MIPI CSI-2 bridge media driver. Signed-off-by: Paul Kocialkowski --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0644128640fb..a1352171778b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -709,6 +709,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml F: drivers/media/platform/sunxi/sun4i-csi/ +ALLWINNER A31 MIPI CSI-2 BRIDGE +M: Paul Kocialkowski +L: linux-media at vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml +F: drivers/media/platform/sunxi/sun6i-mipi-csi2/ + ALLWINNER CPUFREQ DRIVER M: Yangtao Li L: linux-pm at vger.kernel.org -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:39 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:39 +0100 Subject: [PATCH v2 19/19] MAINTAINERS: Add entry for the Allwinner A83T MIPI CSI-2 bridge In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-20-paul.kocialkowski@bootlin.com> Add myself as maintainer of the A83T MIPI CSI-2 bridge media driver. Signed-off-by: Paul Kocialkowski --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a1352171778b..3b48612657b6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -717,6 +717,14 @@ T: git git://linuxtv.org/media_tree.git F: Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml F: drivers/media/platform/sunxi/sun6i-mipi-csi2/ +ALLWINNER A83T MIPI CSI-2 BRIDGE +M: Paul Kocialkowski +L: linux-media at vger.kernel.org +S: Maintained +T: git git://linuxtv.org/media_tree.git +F: Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml +F: drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/ + ALLWINNER CPUFREQ DRIVER M: Yangtao Li L: linux-pm at vger.kernel.org -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:38 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:38 +0100 Subject: [PATCH v2 18/19] ARM: dts: sun8i: a83t: Add MIPI CSI-2 controller node In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-19-paul.kocialkowski@bootlin.com> MIPI CSI-2 is supported on the A83T with a dedicated controller that covers both the protocol and D-PHY. It can be connected to the CSI interface as a V4L2 subdev through the fwnode graph. This is not done by default since connecting the bridge without a subdev attached to it will cause a failure on the CSI driver. Signed-off-by: Paul Kocialkowski --- arch/arm/boot/dts/sun8i-a83t.dtsi | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi index 3ce030f7e05d..ee19cbb565a6 100644 --- a/arch/arm/boot/dts/sun8i-a83t.dtsi +++ b/arch/arm/boot/dts/sun8i-a83t.dtsi @@ -1076,6 +1076,32 @@ csi_in_mipi_csi2_bridge: port at 1 { }; }; + mipi_csi2: csi at 1cb1000 { + compatible = "allwinner,sun8i-a83t-mipi-csi2"; + reg = <0x01cb1000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_CSI_SCLK>, + <&ccu CLK_MIPI_CSI>, + <&ccu CLK_CSI_MISC>; + clock-names = "bus", "mod", "mipi", "misc"; + resets = <&ccu RST_BUS_CSI>; + status = "disabled"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mipi_csi2_in: port at 0 { + reg = <0>; + }; + + mipi_csi2_out: port at 1 { + reg = <1>; + }; + }; + }; + hdmi: hdmi at 1ee0000 { compatible = "allwinner,sun8i-a83t-dw-hdmi"; reg = <0x01ee0000 0x10000>; -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:36 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:36 +0100 Subject: [PATCH v2 16/19] dt-bindings: media: Add A83T MIPI CSI-2 bindings documentation In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-17-paul.kocialkowski@bootlin.com> This introduces YAML bindings documentation for the A83T MIPI CSI-2 controller. Signed-off-by: Paul Kocialkowski --- .../media/allwinner,sun8i-a83t-mipi-csi2.yaml | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml new file mode 100644 index 000000000000..78309084f904 --- /dev/null +++ b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml @@ -0,0 +1,147 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-mipi-csi2.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Allwinner A83T MIPI CSI-2 Device Tree Bindings + +maintainers: + - Paul Kocialkowski + +properties: + compatible: + const: allwinner,sun8i-a83t-mipi-csi2 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Bus Clock + - description: Module Clock + - description: MIPI-specific Clock + - description: Misc CSI Clock + + clock-names: + items: + - const: bus + - const: mod + - const: mipi + - const: misc + + resets: + maxItems: 1 + + # See ./video-interfaces.txt for details + ports: + type: object + + properties: + port at 0: + type: object + description: Input port, connect to a MIPI CSI-2 sensor + + properties: + reg: + const: 0 + + endpoint: + type: object + + properties: + remote-endpoint: true + + clock-lanes: + maxItems: 1 + + data-lanes: + minItems: 1 + maxItems: 4 + + required: + - data-lanes + - remote-endpoint + + required: + - endpoint + + additionalProperties: false + + port at 1: + type: object + description: Output port, connect to a CSI controller + + properties: + reg: + const: 1 + + endpoint: + type: object + + properties: + remote-endpoint: true + + bus-type: + const: 4 + + required: + - endpoint + + additionalProperties: false + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - resets + +additionalProperties: false + +examples: + - | + #include + #include + #include + + mipi_csi2: csi at 1cb1000 { + compatible = "allwinner,sun8i-a83t-mipi-csi2"; + reg = <0x01cb1000 0x1000>; + interrupts = ; + clocks = <&ccu CLK_BUS_CSI>, + <&ccu CLK_CSI_SCLK>, + <&ccu CLK_MIPI_CSI>, + <&ccu CLK_CSI_MISC>; + clock-names = "bus", "mod", "mipi", "misc"; + resets = <&ccu RST_BUS_CSI>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + mipi_csi2_in: port at 0 { + reg = <0>; + + mipi_csi2_in_ov8865: endpoint { + data-lanes = <1 2 3 4>; + + remote-endpoint = <&ov8865_out_mipi_csi2>; + }; + }; + + mipi_csi2_out: port at 1 { + reg = <1>; + + mipi_csi2_out_csi: endpoint { + remote-endpoint = <&csi_in_mipi_csi2>; + }; + }; + }; + }; + +... -- 2.29.2 From paul.kocialkowski at bootlin.com Sat Nov 28 14:28:37 2020 From: paul.kocialkowski at bootlin.com (Paul Kocialkowski) Date: Sat, 28 Nov 2020 15:28:37 +0100 Subject: [PATCH v2 17/19] media: sunxi: Add support for the A83T MIPI CSI-2 controller In-Reply-To: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> References: <20201128142839.517949-1-paul.kocialkowski@bootlin.com> Message-ID: <20201128142839.517949-18-paul.kocialkowski@bootlin.com> The A83T supports MIPI CSI-2 with a composite controller, covering both the protocol logic and the D-PHY implementation. This controller seems to be found on the A83T only and probably was abandoned since. This implementation splits the protocol and D-PHY registers and uses the PHY framework internally. The D-PHY is not registered as a standalone PHY driver since it cannot be used with any other controller. There are a few notable points about the controller: - The initialisation sequence involes writing specific magic init values that do not seem to make any particular sense given the concerned register fields. - Interrupts appear to be hitting regardless of the interrupt mask registers, which can cause a serious flood when transmission errors occur. Only 8-bit and 10-bit Bayer formats are currently supported. While up to 4 internal channels to the CSI controller exist, only one is currently supported by this implementation. This work is based on the first version of the driver submitted by K?vin L'h?pital, which was adapted to mainline from the Allwinner BSP. This version integrates MIPI CSI-2 support as a standalone V4L2 subdev instead of merging it in the sun6i-csi driver. It was tested on a Banana Pi M3 board with an OV8865 sensor in a 4-lane configuration. Signed-off-by: Paul Kocialkowski --- drivers/media/platform/sunxi/Kconfig | 1 + drivers/media/platform/sunxi/Makefile | 1 + .../sunxi/sun8i-a83t-mipi-csi2/Kconfig | 11 + .../sunxi/sun8i-a83t-mipi-csi2/Makefile | 4 + .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c | 92 +++ .../sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h | 39 ++ .../sun8i_a83t_mipi_csi2.c | 657 ++++++++++++++++++ .../sun8i_a83t_mipi_csi2.h | 197 ++++++ 8 files changed, 1002 insertions(+) create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c create mode 100644 drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig index 9684e07454ad..db4c07be7e4c 100644 --- a/drivers/media/platform/sunxi/Kconfig +++ b/drivers/media/platform/sunxi/Kconfig @@ -3,3 +3,4 @@ source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig" +source "drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index 887a7cae8fca..9aa01cb01883 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -3,5 +3,6 @@ obj-y += sun4i-csi/ obj-y += sun6i-csi/ obj-y += sun6i-mipi-csi2/ +obj-y += sun8i-a83t-mipi-csi2/ obj-y += sun8i-di/ obj-y += sun8i-rotate/ diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig new file mode 100644 index 000000000000..162f5d1dc25f --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_SUN8I_A83T_MIPI_CSI2 + tristate "Allwinner A83T MIPI CSI-2 Controller and D-PHY Driver" + depends on VIDEO_V4L2 && COMMON_CLK + depends on ARCH_SUNXI || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select REGMAP_MMIO + select V4L2_FWNODE + help + Support for the Allwinner A83T MIPI CSI-2 Controller and D-PHY. diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile new file mode 100644 index 000000000000..1427d15a879a --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only +sun8i-a83t-mipi-csi2-y += sun8i_a83t_mipi_csi2.o sun8i_a83t_dphy.o + +obj-$(CONFIG_VIDEO_SUN8I_A83T_MIPI_CSI2) += sun8i-a83t-mipi-csi2.o diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c new file mode 100644 index 000000000000..ebb504247956 --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#include +#include + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" + +static int sun8i_a83t_dphy_set_mode(struct phy *dphy, enum phy_mode mode, + int submode) +{ + if (mode != PHY_MODE_MIPI_DPHY || + submode != PHY_MIPI_DPHY_SUBMODE_RX) + return -EINVAL; + + return 0; +}; + +static int sun8i_a83t_dphy_configure(struct phy *dphy, + union phy_configure_opts *opts) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = phy_get_drvdata(dphy); + int ret; + + ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); + if (ret) + return ret; + + memcpy(&cdev->dphy_config, opts, sizeof(cdev->dphy_config)); + + return 0; +}; + +static int sun8i_a83t_dphy_power_on(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = phy_get_drvdata(dphy); + struct regmap *regmap = cdev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_RESET_N | + SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N); + + regmap_write(regmap, SUN8I_A83T_DPHY_ANA0_REG, + SUN8I_A83T_DPHY_ANA0_REXT_EN | + SUN8I_A83T_DPHY_ANA0_RINT(2) | + SUN8I_A83T_DPHY_ANA0_SNK(2)); + + return 0; +}; + +static int sun8i_a83t_dphy_power_off(struct phy *dphy) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = phy_get_drvdata(dphy); + struct regmap *regmap = cdev->regmap; + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + + return 0; +}; + +static struct phy_ops sun8i_a83t_dphy_ops = { + .set_mode = sun8i_a83t_dphy_set_mode, + .configure = sun8i_a83t_dphy_configure, + .power_on = sun8i_a83t_dphy_power_on, + .power_off = sun8i_a83t_dphy_power_off, +}; + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_dev *cdev) +{ + struct phy_provider *phy_provider; + + cdev->dphy = devm_phy_create(cdev->dev, NULL, &sun8i_a83t_dphy_ops); + if (IS_ERR(cdev->dphy)) { + dev_err(cdev->dev, "failed to create D-PHY\n"); + return PTR_ERR(cdev->dphy); + } + + phy_set_drvdata(cdev->dphy, cdev); + + phy_provider = devm_of_phy_provider_register(cdev->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(cdev->dev, "failed to register D-PHY provider\n"); + return PTR_ERR(phy_provider); + } + + return 0; +} diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h new file mode 100644 index 000000000000..a4ed355e5f6f --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 K?vin L'h?pital + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#ifndef __SUN8I_A83T_DPHY_H__ +#define __SUN8I_A83T_DPHY_H__ + +#include "sun8i_a83t_mipi_csi2.h" + +#define SUN8I_A83T_DPHY_CTRL_REG 0x10 +#define SUN8I_A83T_DPHY_CTRL_INIT_VALUE 0xb8df698e +#define SUN8I_A83T_DPHY_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_DPHY_CTRL_SHUTDOWN_N BIT(15) +#define SUN8I_A83T_DPHY_CTRL_DEBUG BIT(8) +#define SUN8I_A83T_DPHY_STATUS_REG 0x14 +#define SUN8I_A83T_DPHY_STATUS_CLK_STOP BIT(10) +#define SUN8I_A83T_DPHY_STATUS_CLK_ULPS BIT(9) +#define SUN8I_A83T_DPHY_STATUS_HSCLK BIT(8) +#define SUN8I_A83T_DPHY_STATUS_D3_STOP BIT(7) +#define SUN8I_A83T_DPHY_STATUS_D2_STOP BIT(6) +#define SUN8I_A83T_DPHY_STATUS_D1_STOP BIT(5) +#define SUN8I_A83T_DPHY_STATUS_D0_STOP BIT(4) +#define SUN8I_A83T_DPHY_STATUS_D3_ULPS BIT(3) +#define SUN8I_A83T_DPHY_STATUS_D2_ULPS BIT(2) +#define SUN8I_A83T_DPHY_STATUS_D1_ULPS BIT(1) +#define SUN8I_A83T_DPHY_STATUS_D0_ULPS BIT(0) + +#define SUN8I_A83T_DPHY_ANA0_REG 0x30 +#define SUN8I_A83T_DPHY_ANA0_REXT_EN BIT(31) +#define SUN8I_A83T_DPHY_ANA0_REXT BIT(30) +#define SUN8I_A83T_DPHY_ANA0_RINT(v) (((v) << 28) & GENMASK(29, 28)) +#define SUN8I_A83T_DPHY_ANA0_SNK(v) (((v) << 20) & GENMASK(22, 20)) + +int sun8i_a83t_dphy_register(struct sun8i_a83t_mipi_csi2_dev *cdev); + +#endif /* __SUN8I_A83T_DPHY_H__ */ diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c new file mode 100644 index 000000000000..84132732d40e --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c @@ -0,0 +1,657 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 K?vin L'h?pital + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sun8i_a83t_dphy.h" +#include "sun8i_a83t_mipi_csi2.h" + +#define MODULE_NAME "sun8i-a83t-mipi-csi2" + +static const u32 sun8i_a83t_mipi_csi2_mbus_codes[] = { + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, +}; + +/* Core */ + +static void sun8i_a83t_mipi_csi2_init(struct sun8i_a83t_mipi_csi2_dev *cdev) +{ + struct regmap *regmap = cdev->regmap; + + /* + * The Allwinner BSP sets various magic values on a bunch of registers. + * This is apparently a necessary initialization process that will cause + * the capture to fail with unsolicited interrupts hitting if skipped. + * + * Most of the registers are set to proper values later, except for the + * two reserved registers. They are said to hold a "hardware lock" + * value, without more information available. + */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG, + SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, 0); + regmap_write(regmap, SUN8I_A83T_DPHY_CTRL_REG, + SUN8I_A83T_DPHY_CTRL_INIT_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD1_REG, + SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_RSVD2_REG, + SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, 0); + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE); +} + +/* Video */ + +static int sun8i_a83t_mipi_csi2_s_stream(struct v4l2_subdev *subdev, int on) +{ + struct sun8i_a83t_mipi_csi2_video *video = + sun8i_a83t_mipi_csi2_subdev_video(subdev); + struct sun8i_a83t_mipi_csi2_dev *cdev = + sun8i_a83t_mipi_csi2_video_dev(video); + struct v4l2_subdev *remote_subdev = video->remote_subdev; + struct v4l2_fwnode_bus_mipi_csi2 *bus_mipi_csi2 = + &video->endpoint.bus.mipi_csi2; + union phy_configure_opts dphy_opts = { 0 }; + struct phy_configure_opts_mipi_dphy *dphy_cfg = &dphy_opts.mipi_dphy; + struct regmap *regmap = cdev->regmap; + struct v4l2_ctrl *ctrl; + unsigned int lanes_count; + unsigned int bpp; + unsigned long pixel_rate; + u8 data_type = 0; + u32 version = 0; + /* Initialize to 0 to use both in disable label (ret != 0) and off. */ + int ret = 0; + + if (!remote_subdev) + return -ENODEV; + + if (!on) { + v4l2_subdev_call(remote_subdev, video, s_stream, 0); + goto disable; + } + + switch (video->mbus_format.code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + data_type = MIPI_CSI2_DATA_TYPE_RAW8; + bpp = 8; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + data_type = MIPI_CSI2_DATA_TYPE_RAW10; + bpp = 10; + break; + default: + return -EINVAL; + } + + /* Sensor pixel rate */ + + ctrl = v4l2_ctrl_find(remote_subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(cdev->dev, + "%s: no MIPI CSI-2 pixel rate from the sensor\n", + __func__); + return -ENODEV; + } + + pixel_rate = (unsigned long)v4l2_ctrl_g_ctrl_int64(ctrl); + if (!pixel_rate) { + dev_err(cdev->dev, + "%s: zero MIPI CSI-2 pixel rate from the sensor\n", + __func__); + return -ENODEV; + } + + /* Power management */ + + ret = pm_runtime_get_sync(cdev->dev); + if (ret < 0) { + pm_runtime_put_noidle(cdev->dev); + return ret; + } + + /* D-PHY configuration */ + + lanes_count = bus_mipi_csi2->num_data_lanes; + phy_mipi_dphy_get_default_config(pixel_rate, bpp, lanes_count, + dphy_cfg); + + /* + * Note that our hardware is using DDR, which is not taken in account by + * phy_mipi_dphy_get_default_config when calculating hs_clk_rate from + * the pixel rate, lanes count and bpp. + * + * The resulting clock rate is basically the symbol rate over the whole + * link. The actual clock rate is calculated with division by two since + * DDR samples both on rising and falling edges. + */ + + dev_dbg(cdev->dev, "A83T MIPI CSI-2 config:\n"); + dev_dbg(cdev->dev, + "%ld pixels/s, %u bits/pixel, %u lanes, %lu Hz clock\n", + pixel_rate, bpp, lanes_count, dphy_cfg->hs_clk_rate / 2); + + ret = phy_reset(cdev->dphy); + if (ret) { + dev_err(cdev->dev, "failed to reset MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_set_mode_ext(cdev->dphy, PHY_MODE_MIPI_DPHY, + PHY_MIPI_DPHY_SUBMODE_RX); + if (ret) { + dev_err(cdev->dev, "failed to set MIPI D-PHY mode\n"); + goto error_pm; + } + + ret = phy_configure(cdev->dphy, &dphy_opts); + if (ret) { + dev_err(cdev->dev, "failed to configure MIPI D-PHY\n"); + goto error_pm; + } + + ret = phy_power_on(cdev->dphy); + if (ret) { + dev_err(cdev->dev, "failed to power on MIPI D-PHY\n"); + goto error_pm; + } + + /* MIPI CSI-2 controller setup */ + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, + SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N); + + regmap_read(regmap, SUN8I_A83T_MIPI_CSI2_VERSION_REG, &version); + + dev_dbg(cdev->dev, "A83T MIPI CSI-2 version: %04x\n", version); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN | + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(8) | + SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(1) | + SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(lanes_count)); + + /* + * Our MIPI CSI-2 controller has internal channels that can be + * configured to match a specific MIPI CSI-2 virtual channel and/or + * a specific data type. Each internal channel can be piped to an + * internal channel of the CSI controller. + * + * We set virtual channel numbers to all channels to make sure that + * virtual channel 0 goes to CSI channel 0 only. + */ + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_VCDT0_REG, + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(3, 3) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(2, 2) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(1, 1) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(0, 0) | + SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(0, data_type)); + + /* Start streaming. */ + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN); + + ret = v4l2_subdev_call(remote_subdev, video, s_stream, 1); + if (ret) + goto disable; + + return 0; + +disable: + regmap_update_bits(regmap, SUN8I_A83T_MIPI_CSI2_CFG_REG, + SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN, 0); + + regmap_write(regmap, SUN8I_A83T_MIPI_CSI2_CTRL_REG, 0); + + phy_power_off(cdev->dphy); + +error_pm: + pm_runtime_put(cdev->dev); + + return ret; +} + +static const +struct v4l2_subdev_video_ops sun8i_a83t_mipi_csi2_subdev_video_ops = { + .s_stream = sun8i_a83t_mipi_csi2_s_stream, +}; + +/* Pad */ + +static int +sun8i_a83t_mipi_csi2_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(sun8i_a83t_mipi_csi2_mbus_codes)) + return -EINVAL; + + code_enum->code = sun8i_a83t_mipi_csi2_mbus_codes[code_enum->index]; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_get_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_video *video = + sun8i_a83t_mipi_csi2_subdev_video(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *mbus_format = *v4l2_subdev_get_try_format(subdev, config, + format->pad); + else + *mbus_format = video->mbus_format; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_set_fmt(struct v4l2_subdev *subdev, + struct v4l2_subdev_pad_config *config, + struct v4l2_subdev_format *format) +{ + struct sun8i_a83t_mipi_csi2_video *video = + sun8i_a83t_mipi_csi2_subdev_video(subdev); + struct v4l2_mbus_framefmt *mbus_format = &format->format; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + *v4l2_subdev_get_try_format(subdev, config, format->pad) = + *mbus_format; + else + video->mbus_format = *mbus_format; + + return 0; +} + +static const struct v4l2_subdev_pad_ops sun8i_a83t_mipi_csi2_subdev_pad_ops = { + .enum_mbus_code = sun8i_a83t_mipi_csi2_enum_mbus_code, + .get_fmt = sun8i_a83t_mipi_csi2_get_fmt, + .set_fmt = sun8i_a83t_mipi_csi2_set_fmt, +}; + +/* Subdev */ + +static const struct v4l2_subdev_ops sun8i_a83t_mipi_csi2_subdev_ops = { + .video = &sun8i_a83t_mipi_csi2_subdev_video_ops, + .pad = &sun8i_a83t_mipi_csi2_subdev_pad_ops, +}; + +/* Notifier */ + +static int +sun8i_a83t_mipi_csi2_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *remote_subdev, + struct v4l2_async_subdev *remote_subdev_async) +{ + struct v4l2_subdev *subdev = notifier->sd; + struct sun8i_a83t_mipi_csi2_video *video = + sun8i_a83t_mipi_csi2_subdev_video(subdev); + struct sun8i_a83t_mipi_csi2_dev *cdev = + sun8i_a83t_mipi_csi2_video_dev(video); + int source_pad; + int ret; + + source_pad = media_entity_get_fwnode_pad(&remote_subdev->entity, + remote_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) + return source_pad; + + ret = media_create_pad_link(&remote_subdev->entity, source_pad, + &subdev->entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(cdev->dev, "failed to create %s:%u -> %s:%u link\n", + remote_subdev->entity.name, source_pad, + subdev->entity.name, 0); + return ret; + } + + video->remote_subdev = remote_subdev; + + return 0; +} + +static const +struct v4l2_async_notifier_operations sun8i_a83t_mipi_csi2_notifier_ops = { + .bound = sun8i_a83t_mipi_csi2_notifier_bound, +}; + +/* Media Entity */ + +static const struct media_entity_operations sun8i_a83t_mipi_csi2_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +/* Base Driver */ + +static int __maybe_unused sun8i_a83t_mipi_csi2_suspend(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = dev_get_drvdata(dev); + + clk_disable_unprepare(cdev->clk_misc); + clk_disable_unprepare(cdev->clk_mipi); + clk_disable_unprepare(cdev->clk_mod); + clk_disable_unprepare(cdev->clk_bus); + reset_control_assert(cdev->reset); + + return 0; +} + +static int __maybe_unused sun8i_a83t_mipi_csi2_resume(struct device *dev) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(cdev->reset); + if (ret) { + dev_err(cdev->dev, "failed to deassert reset\n"); + return ret; + } + + ret = clk_prepare_enable(cdev->clk_bus); + if (ret) { + dev_err(cdev->dev, "failed to enable bus clock\n"); + goto error_reset; + } + + ret = clk_prepare_enable(cdev->clk_mod); + if (ret) { + dev_err(cdev->dev, "failed to enable module clock\n"); + goto error_clk_bus; + } + + ret = clk_prepare_enable(cdev->clk_mipi); + if (ret) { + dev_err(cdev->dev, "failed to enable MIPI clock\n"); + goto error_clk_mod; + } + + ret = clk_prepare_enable(cdev->clk_misc); + if (ret) { + dev_err(cdev->dev, "failed to enable CSI misc clock\n"); + goto error_clk_mipi; + } + + sun8i_a83t_mipi_csi2_init(cdev); + + return 0; + +error_clk_mipi: + clk_disable_unprepare(cdev->clk_mipi); + +error_clk_mod: + clk_disable_unprepare(cdev->clk_mod); + +error_clk_bus: + clk_disable_unprepare(cdev->clk_bus); + +error_reset: + reset_control_assert(cdev->reset); + + return ret; +} + +static int +sun8i_a83t_mipi_csi2_v4l2_setup(struct sun8i_a83t_mipi_csi2_dev *cdev) +{ + struct sun8i_a83t_mipi_csi2_video *video = &cdev->video; + struct v4l2_subdev *subdev = &video->subdev; + struct v4l2_async_notifier *notifier = &video->notifier; + struct fwnode_handle *handle; + struct v4l2_fwnode_endpoint *endpoint; + struct v4l2_async_subdev *subdev_async; + int ret; + + /* Subdev */ + + v4l2_subdev_init(subdev, &sun8i_a83t_mipi_csi2_subdev_ops); + subdev->dev = cdev->dev; + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strscpy(subdev->name, MODULE_NAME, sizeof(subdev->name)); + v4l2_set_subdevdata(subdev, cdev); + + /* Entity */ + + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + subdev->entity.ops = &sun8i_a83t_mipi_csi2_entity_ops; + + /* Pads */ + + video->pads[0].flags = MEDIA_PAD_FL_SINK; + video->pads[1].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&subdev->entity, 2, video->pads); + if (ret) + return ret; + + /* Endpoint */ + + handle = fwnode_graph_get_endpoint_by_id(dev_fwnode(cdev->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + if (!handle) { + ret = -ENODEV; + goto error_media_entity; + } + + endpoint = &video->endpoint; + endpoint->bus_type = V4L2_MBUS_CSI2_DPHY; + + ret = v4l2_fwnode_endpoint_parse(handle, endpoint); + fwnode_handle_put(handle); + if (ret) + goto error_media_entity; + + /* Notifier */ + + v4l2_async_notifier_init(notifier); + + subdev_async = &video->subdev_async; + ret = v4l2_async_notifier_add_fwnode_remote_subdev(notifier, handle, + subdev_async); + if (ret) + goto error_media_entity; + + video->notifier.ops = &sun8i_a83t_mipi_csi2_notifier_ops; + + ret = v4l2_async_subdev_notifier_register(subdev, notifier); + if (ret < 0) + goto error_notifier; + + /* Subdev */ + + ret = v4l2_async_register_subdev(subdev); + if (ret < 0) + goto error_notifier_registered; + + /* Runtime PM */ + + pm_runtime_enable(cdev->dev); + pm_runtime_set_suspended(cdev->dev); + + return 0; + +error_notifier_registered: + v4l2_async_notifier_unregister(notifier); +error_notifier: + v4l2_async_notifier_cleanup(notifier); +error_media_entity: + media_entity_cleanup(&subdev->entity); + + return ret; +} + +static int +sun8i_a83t_mipi_csi2_v4l2_teardown(struct sun8i_a83t_mipi_csi2_dev *cdev) +{ + struct sun8i_a83t_mipi_csi2_video *video = &cdev->video; + struct v4l2_subdev *subdev = &video->subdev; + struct v4l2_async_notifier *notifier = &video->notifier; + + v4l2_async_unregister_subdev(subdev); + v4l2_async_notifier_unregister(notifier); + v4l2_async_notifier_cleanup(notifier); + media_entity_cleanup(&subdev->entity); + v4l2_device_unregister_subdev(subdev); + + return 0; +} + +static const struct regmap_config sun8i_a83t_mipi_csi2_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = 0x120, +}; + +static int sun8i_a83t_mipi_csi2_probe(struct platform_device *pdev) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev; + struct resource *res; + void __iomem *io_base; + int ret; + + cdev = devm_kzalloc(&pdev->dev, sizeof(*cdev), GFP_KERNEL); + if (!cdev) + return -ENOMEM; + + cdev->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + cdev->regmap = + devm_regmap_init_mmio(&pdev->dev, io_base, + &sun8i_a83t_mipi_csi2_regmap_config); + if (IS_ERR(cdev->regmap)) { + dev_err(&pdev->dev, "failed to init register map\n"); + return PTR_ERR(cdev->regmap); + } + + cdev->clk_bus = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(cdev->clk_bus)) { + dev_err(&pdev->dev, "failed to acquire bus clock\n"); + return PTR_ERR(cdev->clk_bus); + } + + cdev->clk_mod = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(cdev->clk_mod)) { + dev_err(&pdev->dev, "failed to acquire mod clock\n"); + return PTR_ERR(cdev->clk_mod); + } + + cdev->clk_mipi = devm_clk_get(&pdev->dev, "mipi"); + if (IS_ERR(cdev->clk_mipi)) { + dev_err(&pdev->dev, "failed to acquire mipi clock\n"); + return PTR_ERR(cdev->clk_mipi); + } + + cdev->clk_misc = devm_clk_get(&pdev->dev, "misc"); + if (IS_ERR(cdev->clk_misc)) { + dev_err(&pdev->dev, "failed to acquire misc clock\n"); + return PTR_ERR(cdev->clk_misc); + } + + cdev->reset = devm_reset_control_get_shared(&pdev->dev, NULL); + if (IS_ERR(cdev->reset)) { + dev_err(&pdev->dev, "failed to get reset controller\n"); + return PTR_ERR(cdev->reset); + } + + ret = sun8i_a83t_dphy_register(cdev); + if (ret) { + dev_err(&pdev->dev, "failed to init MIPI D-PHY\n"); + return ret; + } + + platform_set_drvdata(pdev, cdev); + + ret = sun8i_a83t_mipi_csi2_v4l2_setup(cdev); + if (ret) + return ret; + + return 0; +} + +static int sun8i_a83t_mipi_csi2_remove(struct platform_device *pdev) +{ + struct sun8i_a83t_mipi_csi2_dev *cdev = platform_get_drvdata(pdev); + + phy_exit(cdev->dphy); + + return sun8i_a83t_mipi_csi2_v4l2_teardown(cdev); +} + +static const struct dev_pm_ops sun8i_a83t_mipi_csi2_pm_ops = { + SET_RUNTIME_PM_OPS(sun8i_a83t_mipi_csi2_suspend, + sun8i_a83t_mipi_csi2_resume, NULL) +}; + +static const struct of_device_id sun8i_a83t_mipi_csi2_of_match[] = { + { .compatible = "allwinner,sun8i-a83t-mipi-csi2" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match); + +static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = { + .probe = sun8i_a83t_mipi_csi2_probe, + .remove = sun8i_a83t_mipi_csi2_remove, + .driver = { + .name = MODULE_NAME, + .of_match_table = of_match_ptr(sun8i_a83t_mipi_csi2_of_match), + .pm = &sun8i_a83t_mipi_csi2_pm_ops, + }, +}; +module_platform_driver(sun8i_a83t_mipi_csi2_platform_driver); + +MODULE_DESCRIPTION("Allwinner A83T MIPI CSI-2 and D-PHY Controller Driver"); +MODULE_AUTHOR("Paul Kocialkowski "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h new file mode 100644 index 000000000000..5b4e995392bb --- /dev/null +++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2020 K?vin L'h?pital + * Copyright 2020 Bootlin + * Author: Paul Kocialkowski + */ + +#ifndef __SUN8I_A83T_MIPI_CSI2_H__ +#define __SUN8I_A83T_MIPI_CSI2_H__ + +#include +#include +#include +#include +#include + +#define SUN8I_A83T_MIPI_CSI2_VERSION_REG 0x0 +#define SUN8I_A83T_MIPI_CSI2_CTRL_REG 0x4 +#define SUN8I_A83T_MIPI_CSI2_CTRL_INIT_VALUE 0xb8c39bec +#define SUN8I_A83T_MIPI_CSI2_CTRL_RESET_N BIT(31) +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_REG 0x8 +#define SUN8I_A83T_MIPI_CSI2_RX_PKT_NUM_INIT_VALUE 0xb8d257f8 +#define SUN8I_A83T_MIPI_CSI2_RSVD0_REG 0xc + +#define SUN8I_A83T_MIPI_CSI2_RSVD1_REG 0x18 +#define SUN8I_A83T_MIPI_CSI2_RSVD1_HW_LOCK_VALUE 0xb8c8a30c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_REG 0x1c +#define SUN8I_A83T_MIPI_CSI2_RSVD2_HW_LOCK_VALUE 0xb8df8ad7 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_REG 0x20 +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_REG 0x24 +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT7 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT6 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT5 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LINE_SEQ_ERR_DT4 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT7 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT6 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT5 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_LS_LE_ERR_DT4 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_STA1_ESC_ENTRY_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_REG 0x28 +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_ECC_ERR_DBL BIT(28) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC3 BIT(27) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC2 BIT(26) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC1 BIT(25) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CKSM_ERR_VC0 BIT(24) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT3 BIT(23) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT2 BIT(22) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT1 BIT(21) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LINE_SEQ_ERR_DT0 BIT(20) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT3 BIT(19) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT2 BIT(18) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT1 BIT(17) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_LS_LE_ERR_DT0 BIT(16) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_CRC_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FRM_SEQ_ERR_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_FS_FE_ERR_VC0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK0_SOT_SYNC_ERR_0 BIT(0) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_REG 0x2c +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC3 BIT(15) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC2 BIT(14) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC1 BIT(13) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_DT_ERR_VC0 BIT(12) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC3 BIT(11) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC2 BIT(10) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC1 BIT(9) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ECC_ERR1_VC0 BIT(8) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_3 BIT(7) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_2 BIT(6) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_1 BIT(5) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_SOT_ERR_0 BIT(4) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_3 BIT(3) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_2 BIT(2) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_1 BIT(1) +#define SUN8I_A83T_MIPI_CSI2_INT_MSK1_ESC_ENTRY_ERR_0 BIT(0) + +#define SUN8I_A83T_MIPI_CSI2_CFG_REG 0x100 +#define SUN8I_A83T_MIPI_CSI2_CFG_INIT_VALUE 0xb8c64f24 +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_EN BIT(31) +#define SUN8I_A83T_MIPI_CSI2_CFG_BYPASS_ECC_EN BIT(29) +#define SUN8I_A83T_MIPI_CSI2_CFG_UNPKT_EN BIT(28) +#define SUN8I_A83T_MIPI_CSI2_CFG_NONE_UNPKT_RX_MODE BIT(27) +#define SUN8I_A83T_MIPI_CSI2_CFG_YC_SWAB BIT(26) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_BYTE BIT(24) +#define SUN8I_A83T_MIPI_CSI2_CFG_SYNC_DLY_CYCLE(v) (((v) << 18) & \ + GENMASK(22, 18)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_CHANNEL(v) ((((v) - 1) << 16) & \ + GENMASK(17, 16)) +#define SUN8I_A83T_MIPI_CSI2_CFG_N_LANE(v) ((((v) - 1) << 4) & \ + GENMASK(5, 4)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_REG 0x104 +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + ((ch) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT0_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + ((ch) * 8)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_REG 0x108 +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_VC(ch, vc) (((vc) & GENMASK(1, 0)) << \ + (((ch) - 4) * 8 + 6)) +#define SUN8I_A83T_MIPI_CSI2_VCDT1_CH_DT(ch, t) (((t) & GENMASK(5, 0)) << \ + (((ch) - 4) * 8)) + +enum mipi_csi2_data_type { + MIPI_CSI2_DATA_TYPE_RAW8 = 0x2a, + MIPI_CSI2_DATA_TYPE_RAW10 = 0x2b, + MIPI_CSI2_DATA_TYPE_RAW12 = 0x2c, +}; + +struct sun8i_a83t_mipi_csi2_video { + struct v4l2_fwnode_endpoint endpoint; + struct v4l2_subdev subdev; + struct media_pad pads[2]; + + struct v4l2_async_subdev subdev_async; + struct v4l2_async_notifier notifier; + + struct v4l2_subdev *remote_subdev; + + struct v4l2_mbus_framefmt mbus_format; +}; + +struct sun8i_a83t_mipi_csi2_dev { + struct device *dev; + + struct regmap *regmap; + struct clk *clk_bus; + struct clk *clk_mod; + struct clk *clk_mipi; + struct clk *clk_misc; + struct reset_control *reset; + struct phy *dphy; + struct phy_configure_opts_mipi_dphy dphy_config; + + struct sun8i_a83t_mipi_csi2_video video; +}; + +#define sun8i_a83t_mipi_csi2_subdev_video(subdev) \ + container_of(subdev, struct sun8i_a83t_mipi_csi2_video, subdev) + +#define sun8i_a83t_mipi_csi2_video_dev(video) \ + container_of(video, struct sun8i_a83t_mipi_csi2_dev, video) + +#endif /* __SUN8I_A83T_MIPI_CSI2_H__ */ -- 2.29.2 From nicolaswong730 at gmail.com Sun Nov 29 01:52:48 2020 From: nicolaswong730 at gmail.com (Dr. Nicolas Wong) Date: Sun, 29 Nov 2020 02:52:48 +0100 Subject: Good Morning, Message-ID: -- I'm Dr. Nicolas Wong, did you Receive the (FUND), that was paid to you? please, do not hesitate to Let me know with your full name:.. for immediate verification notice, Thanks, Dr. Nicolas Wong Foreign Remittance Director Sincerely Yours, Respectfully, Mr Bill T Winters, Group Chief Executive Officer & Executive Director, From mrhanialmuhanna at gmx.com Sun Nov 29 09:48:04 2020 From: mrhanialmuhanna at gmx.com (MR JABER AL-GHAFR) Date: Sun, 29 Nov 2020 10:48:04 +0100 Subject: Re.Investment Message-ID: Good Day I am JABER AL-GHAFRI, Pleasant greetings to you as i seek your indulgence to introduce to you the desire of my principal?s wish, to make huge financial investment in your home country on areas of oil and gas, real estate, tourism and hotel, manufacturing and production company, agriculture, fishing, Mining & Trading of natural resources such as crude oil, coal, graphite, coke, refinery, energy, hospital etc. He needs a capable, trustworthy and understanding business partner, who can confidently handle and manage his investment funds with utmost care of secrecy without traces or link to him as he is politically exposed at the moment in his country. He has a huge available financial portfolio. Please, I will provide more details about the transaction if you are sure you can handle classified information and also let me know your entitlement for the solicited role I shall be expecting your quick reply.email ?alghafrij13 at gmail.com Best Regards, JABER AL-GHAFR -- This email has been checked for viruses by AVG. https://www.avg.com From mariah_blanchett1875 at yahoo.com Sun Nov 29 17:34:27 2020 From: mariah_blanchett1875 at yahoo.com (Mariah Blanchett) Date: Sun, 29 Nov 2020 17:34:27 +0000 (UTC) Subject: From Mariah Blanchett Johnson References: <744628906.1562915.1606671267301.ref@mail.yahoo.com> Message-ID: <744628906.1562915.1606671267301@mail.yahoo.com> >From Mariah Blanchett Johnson Hello Dear friend I have sent you this e-mail for open discussions with you. I don't want you to misunderstand this offer in any aspect...if it is okay with you, I ask for your full cooperation. I have contacted you base on trust to handle an investment in your country/company on my behalf as a prospective partner. My name is Mariah Blanchett Johnson It might interest you to know that I have US$3.600, 000.00, Three million Six Hundred thousand deposited by late father with a financial institution I want your partnership for investing the fund in your country/company. It is pertinent to ask if you can handle this fund/investment in your country, in any of this area 1). telecommunications 2). Transportation industry 3). Five star hotel 4). property (5) Companies, Meanwhile, I am very honest in my dealings with people and I also demand the same from you as a Partner to be. Can I trust you with this fund? I want you to note that this is a mutual business venture there is a reward for your assistance. I shall let you know your benefit for your assistance as we proceed. For a more comprehensively about details of the fund, please contact me as soon as possible. If you find this letter offensive, please ignore it and accept my apologies. Regards, Mariah Blanchett Johnson From nhenry61 at yahoo.com Sun Nov 29 17:36:25 2020 From: nhenry61 at yahoo.com (MR JABER AL-GHAFR) Date: Sun, 29 Nov 2020 18:36:25 +0100 Subject: Re.Investment Message-ID: Good Day I am JABER AL-GHAFRI, Pleasant greetings to you as i seek your indulgence to introduce to you the desire of my principal?s wish, to make huge financial investment in your home country on areas of oil and gas, real estate, tourism and hotel, manufacturing and production company, agriculture, fishing, Mining & Trading of natural resources such as crude oil, coal, graphite, coke, refinery, energy, hospital etc. He needs a capable, trustworthy and understanding business partner, who can confidently handle and manage his investment funds with utmost care of secrecy without traces or link to him as he is politically exposed at the moment in his country. He has a huge available financial portfolio. Please, I will provide more details about the transaction if you are sure you can handle classified information and also let me know your entitlement for the solicited role I shall be expecting your quick reply.email ?alghafrij13 at gmail.com Best Regards, JABER AL-GHAFR -- This email has been checked for viruses by AVG. https://www.avg.com From vkoul at kernel.org Mon Nov 30 10:30:23 2020 From: vkoul at kernel.org (Vinod Koul) Date: Mon, 30 Nov 2020 16:00:23 +0530 Subject: [PATCH 1/8] phy: phy-hi3670-usb3: move driver from staging into phy In-Reply-To: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> References: <420faf39bb03d07f8823b03bc55a429e975e23a0.1605530560.git.mchehab+huawei@kernel.org> Message-ID: <20201130103023.GM8403@vkoul-mobl> On 16-11-20, 13:59, Mauro Carvalho Chehab wrote: > +#define CTRL7_USB2_REFCLKSEL_MASK (3 << 3) > +#define CTRL7_USB2_REFCLKSEL_ABB (3 << 3) > +#define CTRL7_USB2_REFCLKSEL_PAD (2 << 3) This should use GENMASK() > + > +#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23) > + > +#define CFG54_USB31PHY_CR_ADDR_MASK (0xFFFF) > +#define CFG54_USB31PHY_CR_ADDR_SHIFT (16) We can skip this by using FIELD_GET/FIELD_SET macros and only define register fields. > +static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction) > +{ > + int ret; > + > + if (direction) > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_WR_EN, > + CFG54_USB31PHY_CR_WR_EN); > + else > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_RD_EN, > + CFG54_USB31PHY_CR_RD_EN); how about: if direction reg = CFG54_USB31PHY_CR_WR_EN; else reg = CFG54_USB31PHY_CR_RD_EN; regmap_update_bits(usb31misc, USB_MISC_CFG54, reg, reg); > + > + if (ret) > + return ret; > + > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; > + > + ret = regmap_update_bits(usb31misc, USB_MISC_CFG54, > + CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, 0); > + > + return ret; return regmap_update_bits() > +static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc) > +{ > + u32 reg; > + int retry = 100000; > + int ret; > + > + while (retry-- > 0) { > + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > + if (ret) > + return ret; > + if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK) > + return 0; > + > + ret = hi3670_phy_cr_clk(usb31misc); > + if (ret) > + return ret; No delay in between reads..? maybe add a small delay and reduce the retries? > +static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr) > +{ > + u32 reg; > + int ret; > + > + ret = regmap_read(usb31misc, USB_MISC_CFG54, ®); > + if (ret) > + return ret; > + > + reg &= ~(CFG54_USB31PHY_CR_ADDR_MASK << CFG54_USB31PHY_CR_ADDR_SHIFT); > + reg |= ((addr & CFG54_USB31PHY_CR_ADDR_MASK) << CFG54_USB31PHY_CR_ADDR_SHIFT); > + ret = regmap_write(usb31misc, USB_MISC_CFG54, reg); regmap_update_bits() ? > +static int hi3670_is_abbclk_seleted(struct hi3670_priv *priv) > +{ > + u32 reg; > + > + if (!priv->sctrl) { > + dev_err(priv->dev, "priv->sctrl is null!\n"); > + return 1; > + } > + > + if (regmap_read(priv->sctrl, SCTRL_SCDEEPSLEEPED, ®)) { > + dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n"); > + return 1; Not a -ve error code? -- ~Vinod From vkoul at kernel.org Mon Nov 30 10:48:37 2020 From: vkoul at kernel.org (Vinod Koul) Date: Mon, 30 Nov 2020 16:18:37 +0530 Subject: [PATCH v6 0/4] MT7621 PCIe PHY In-Reply-To: <20201121155037.21354-1-sergio.paracuellos@gmail.com> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> Message-ID: <20201130104837.GO8403@vkoul-mobl> On 21-11-20, 16:50, Sergio Paracuellos wrote: > This series adds support for the PCIe PHY found in the Mediatek > MT7621 SoC. > > There is also a 'mt7621-pci' driver which is the controller part > which is still in staging and is a client of this phy. > > Both drivers have been tested together in a gnubee1 board. > > This series are rebased on the top of linux-phy: > commit 768a711e2d4b ("phy: samsung: phy-exynos-pcie: fix typo 'tunning'") Applied, thanks -- ~Vinod From dan.carpenter at oracle.com Mon Nov 30 12:15:07 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Mon, 30 Nov 2020 15:15:07 +0300 Subject: [PATCH v4 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-3-sergio.paracuellos@gmail.com> <20201119053059.GY50232@vkoul-mobl> Message-ID: <20201130121506.GB2767@kadam> On Thu, Nov 19, 2020 at 07:05:22AM +0100, Sergio Paracuellos wrote: > > > +static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) > > > +{ > > > + regmap_write(phy->regmap, reg, val); > > > > Why not use regmap_ calls directly and avoid the dummy wrappers..? > > This is because name was the dummy names are a bit shorter :) but if > it is also necessary I will use directly regmap_ functions. At least don't swap the last two arguments around. regards, dan carpenter From dan.carpenter at oracle.com Mon Nov 30 12:55:10 2020 From: dan.carpenter at oracle.com (Dan Carpenter) Date: Mon, 30 Nov 2020 15:55:10 +0300 Subject: [PATCH 127/141] staging: qlge: Fix fall-through warnings for Clang In-Reply-To: <20201125044257.GA142382@f3> References: <673bd9f27bcc2df8c9d12be94f54001d8066d4ab.1605896060.git.gustavoars@kernel.org> <20201125044257.GA142382@f3> Message-ID: <20201130125510.GF2767@kadam> On Wed, Nov 25, 2020 at 01:42:57PM +0900, Benjamin Poirier wrote: > On 2020-11-20 12:39 -0600, Gustavo A. R. Silva wrote: > > In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning > > by explicitly adding a break statement instead of letting the code fall > > through to the next case. > > > > Link: https://github.com/KSPP/linux/issues/115 > > Signed-off-by: Gustavo A. R. Silva > > --- > > drivers/staging/qlge/qlge_main.c | 1 + > > 1 file changed, 1 insertion(+) > > > > diff --git a/drivers/staging/qlge/qlge_main.c b/drivers/staging/qlge/qlge_main.c > > index 27da386f9d87..c41b1373dcf8 100644 > > --- a/drivers/staging/qlge/qlge_main.c > > +++ b/drivers/staging/qlge/qlge_main.c > > @@ -1385,6 +1385,7 @@ static void ql_categorize_rx_err(struct ql_adapter *qdev, u8 rx_err, > > break; > > case IB_MAC_IOCB_RSP_ERR_CRC: > > stats->rx_crc_err++; > > + break; > > default: > > break; > > } > > In this instance, it think it would be more appropriate to remove the > "default" case. There are checkers which complain about that. (As a static checker developer myself, I think complaining about missing default cases is a waste of everyone's time). regards, dan carpenter From sergio.paracuellos at gmail.com Mon Nov 30 14:31:55 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 30 Nov 2020 15:31:55 +0100 Subject: [PATCH v6 0/4] MT7621 PCIe PHY In-Reply-To: <20201130104837.GO8403@vkoul-mobl> References: <20201121155037.21354-1-sergio.paracuellos@gmail.com> <20201130104837.GO8403@vkoul-mobl> Message-ID: Hi Vinod, On Mon, Nov 30, 2020 at 11:48 AM Vinod Koul wrote: > > On 21-11-20, 16:50, Sergio Paracuellos wrote: > > This series adds support for the PCIe PHY found in the Mediatek > > MT7621 SoC. > > > > There is also a 'mt7621-pci' driver which is the controller part > > which is still in staging and is a client of this phy. > > > > Both drivers have been tested together in a gnubee1 board. > > > > This series are rebased on the top of linux-phy: > > commit 768a711e2d4b ("phy: samsung: phy-exynos-pcie: fix typo 'tunning'") > > Applied, thanks Thanks for letting me know. Best regards, Sergio Paracuellos > > -- > ~Vinod From sergio.paracuellos at gmail.com Mon Nov 30 14:34:26 2020 From: sergio.paracuellos at gmail.com (Sergio Paracuellos) Date: Mon, 30 Nov 2020 15:34:26 +0100 Subject: [PATCH v4 2/4] phy: ralink: Add PHY driver for MT7621 PCIe PHY In-Reply-To: <20201130121506.GB2767@kadam> References: <20201031122246.16497-1-sergio.paracuellos@gmail.com> <20201031122246.16497-3-sergio.paracuellos@gmail.com> <20201119053059.GY50232@vkoul-mobl> <20201130121506.GB2767@kadam> Message-ID: Hi Dan, On Mon, Nov 30, 2020 at 1:15 PM Dan Carpenter wrote: > > On Thu, Nov 19, 2020 at 07:05:22AM +0100, Sergio Paracuellos wrote: > > > > +static inline void phy_write(struct mt7621_pci_phy *phy, u32 val, u32 reg) > > > > +{ > > > > + regmap_write(phy->regmap, reg, val); > > > > > > Why not use regmap_ calls directly and avoid the dummy wrappers..? > > > > This is because name was the dummy names are a bit shorter :) but if > > it is also necessary I will use directly regmap_ functions. > > At least don't swap the last two arguments around. You are right. I don't really know why I changed the order there but those have been deleted in applied series. > > regards, > dan carpenter Best regards, Sergio Paracuellos > From heiko at sntech.de Mon Nov 30 16:28:29 2020 From: heiko at sntech.de (Heiko Stuebner) Date: Mon, 30 Nov 2020 17:28:29 +0100 Subject: (subset) [PATCH v6 0/9] move Rockchip ISP bindings out of staging / add ISP DT nodes for RK3399 In-Reply-To: <20201020193850.1460644-1-helen.koike@collabora.com> References: <20201020193850.1460644-1-helen.koike@collabora.com> Message-ID: <160675369960.1150759.2276623622378204083.b4-ty@sntech.de> On Tue, 20 Oct 2020 16:38:41 -0300, Helen Koike wrote: > Move the bindings out of drivers/staging and place them in > Documentation/devicetree/bindings instead. > > Also, add DT nodes for RK3399 and verify with make ARCH=arm64 dtbs_check > and make ARCH=arm64 dt_binding_check. > > Tested by verifying images streamed from Scarlet Chromebook > > [...] Applied, thanks! [8/9] arm64: dts: rockchip: add isp0 node for rk3399 commit: 97a0115cd96a173369ef30eee2290184921b3f24 [9/9] arm64: dts: rockchip: add isp and sensors for Scarlet commit: ef098edc9c245dd1c150001e22c78e6a3ffd7ff8 Best regards, -- Heiko Stuebner From rkuofungx1 at gmail.com Mon Nov 30 20:06:46 2020 From: rkuofungx1 at gmail.com (max) Date: Mon, 30 Nov 2020 20:06:46 -0000 Subject: Benachrichtigung der Gewinner !!!. Message-ID: <20201130200646.0221585F46@fraxinus.osuosl.org> Benachrichtigung der Gewinner !!!. Ihre E-Mail-ID hat ? 150.000,00 Euro (ein hundertf?nfzigtausend Euro) in LottoMax International Charity program.Ref Well Sp gewonnen /179/0-39/44/4-07/ES.Lucky No.9 / 44/15/27 / 49.For Weitere Informationen und Antragsverfahren , benutzen Sie bitte unser Agent unten in Verbindung; National Post-Code Agency.S.L Mr.Jaime Sanchez E-mail: infocodesl at aol.com Mit Ihren vollst?ndigen Namen, Adresse, Alter, Beruf, Telefonnummern Senden Sie Ihre Antwort auf diese E-Mail: infocodesl at aol.com Hinweis: Dies ist eine internationale Lotterie-Programm. Dieser Eintrag wurde automatisch aus dem Englischen ins Deutschland ?bersetzt. Herzlichen Gl?ckwunsch ! From nhenry61 at yahoo.com Mon Nov 30 22:17:05 2020 From: nhenry61 at yahoo.com (MR JABER AL-GHAFR) Date: Mon, 30 Nov 2020 23:17:05 +0100 Subject: Investment Message-ID: Good Day I am JABER AL-GHAFRI, Pleasant greetings to you as i seek your indulgence to introduce to you the desire of my principal?s wish, to make huge financial investment in your home country on areas of oil and gas, real estate, tourism and hotel, manufacturing and production company, agriculture, fishing, Mining & Trading of natural resources such as crude oil, coal, graphite, coke, refinery, energy, hospital etc. He needs a capable, trustworthy and understanding business partner, who can confidently handle and manage his investment funds with utmost care of secrecy without traces or link to him as he is politically exposed at the moment in his country. He has a huge available financial portfolio. Please, I will provide more details about the transaction if you are sure you can handle classified information and also let me know your entitlement for the solicited role I shall be expecting your quick reply. Email address alghafrij13 at gmail.com Best Regards, JABER AL-GHAFRI -- This email has been checked for viruses by AVG. https://www.avg.com From traviscarter2 at gmail.com Mon Nov 30 23:06:59 2020 From: traviscarter2 at gmail.com (Travis Carter) Date: Mon, 30 Nov 2020 17:06:59 -0600 Subject: [PATCH] staging:media:zoran: Fixed grammar issue Message-ID: <20201130230659.GA10362@linuxmint-midtower-pc> Removed repeated word 'in' Signed-off-by: Travis Carter --- drivers/staging/media/zoran/zoran_card.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c index dfc60e2e9dd7..c77aa458b6d2 100644 --- a/drivers/staging/media/zoran/zoran_card.c +++ b/drivers/staging/media/zoran/zoran_card.c @@ -39,7 +39,7 @@ MODULE_PARM_DESC(card, "Card type"); /* * The video mem address of the video card. The driver has a little database for some videocards * to determine it from there. If your video card is not in there you have either to give it to - * the driver as a parameter or set in in a VIDIOCSFBUF ioctl + * the driver as a parameter or set in a VIDIOCSFBUF ioctl */ static unsigned long vidmem; /* default = 0 - Video memory base address */ -- 2.17.1