i.MX drivers change for 6.1:

- Update i.MX8MP blk-ctrl driver to handle PCIe PHY reset bit.
 - Add interconnect support into i.MX8MP blk-ctrl driver, so that i.MX8MP
   NoC can be set up properly after related power domain is up.
 - Add blk-ctrl support for i.MX8MP HDMI HDCP/HRV and VPU block.
 - Add i.MX93 SRC power domain and MEDIA blk-ctrl driver.
 - Update imx8m-blk-ctrl driver to use genpd_xlate_onecell.
 -----BEGIN PGP SIGNATURE-----
 
 iQFIBAABCgAyFiEEFmJXigPl4LoGSz08UFdYWoewfM4FAmMlib0UHHNoYXduZ3Vv
 QGtlcm5lbC5vcmcACgkQUFdYWoewfM4SPAf7BOfD4bViP+/hxhucfoEYTPShXiBz
 Qrk63cCQlZB72L90AKx+x7TJEdikfTGQwt5xWN1E3d3EepPn4sPuS4aKierHNQZs
 V29ooGSbUdfpYqF+NbyOcIS8qnPJPTlN+0sh6+6eYua8LpR/GQQXH4Zqyj7FiGRE
 p5wPewJVr7lxhWyhmx1f4HUzptEYaNPjYCk3kjslZeyp8gupoX6JdB8zKfJbL+Ho
 KRRuB+dI8bI7HdUJSoz4L6/eshgsUc2WCcYxxhlE2qMrIopX+QbuKvx0ah8bm+lL
 Hj5VrhP5PvywA4gKk/10ESs9YFtC6qQqAf0YEg4bzTzM0LO6CVLC9KpmBQ==
 =DLF5
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmMt0fwACgkQmmx57+YA
 GNnWHQ//SdvIYsj1/U3bZVD9YzzaHablNDz8sKoOnURLRvX9DQcFDpQuLT5dlRAK
 0Z/Hc3ibGpSCTTPjtpGXvLzvjSmbkPf3F4eA0l+tlEc2mNrKpSXXCcktosqDKtRP
 IbEw82ImD+HPa0u6oz3nCR2fV0AZk+xYftEWLDNTLDShFSKUjIJTiQ9luykGXtUd
 980abC9fC4LvcI38pYhuOtS++YBbEwoIzY+GyQbZKXx/IcS1gSk+iANsO8ABvdDt
 6Hmx3ox+6lQrGwlTknd/TkuseWOl1CqkLSwltsAP+0Ijz7uR7PGGuCHReP9q4n1H
 A8QWZ55qskzSxwmytBsgBTlZUfy+OGqOQ387RiOh96jJFX+ANnmg4/c25PX7Vvlf
 i50b9BTLizkL+J82ryqf7tNLtvXg2XW89ajJ0471Vl4OFmsyg4IGjVBT5kNuBF+P
 7DcW6HB2ZtFve0CwIr8o8pHW3of1k6f04z2Tl+Ls73cGcD1S9izuXzBdBSOVixyR
 GxFVjRDbEyta+2yQxzHLIoXx8eYGCxZm1JCiEUaxD44smF82386HfO65pCS2jXZh
 qJg5uCYUNZY/Y6J3bXEZSobxO2jIM5rXpC5NScDf1hAOIMeB7BuPLIeZGfRbcC3l
 OUR3vMG0YNo/MM6VOHE8DFcH8tnEWn9ks4NsUJ1A0DhsKXl41yg=
 =vQBq
 -----END PGP SIGNATURE-----

Merge tag 'imx-drivers-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers

i.MX drivers change for 6.1:

- Update i.MX8MP blk-ctrl driver to handle PCIe PHY reset bit.
- Add interconnect support into i.MX8MP blk-ctrl driver, so that i.MX8MP
  NoC can be set up properly after related power domain is up.
- Add blk-ctrl support for i.MX8MP HDMI HDCP/HRV and VPU block.
- Add i.MX93 SRC power domain and MEDIA blk-ctrl driver.
- Update imx8m-blk-ctrl driver to use genpd_xlate_onecell.

* tag 'imx-drivers-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux: (26 commits)
  soc: imx: add i.MX93 media blk ctrl driver
  soc: imx: add i.MX93 SRC power domain driver
  soc: imx: imx8m-blk-ctrl: Use genpd_xlate_onecell
  soc: imx: imx8mp-blk-ctrl: handle PCIe PHY resets
  soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl
  soc: imx: add i.MX8MP HDMI blk ctrl HDCP/HRV_MWR
  soc: imx: add icc paths for i.MX8MP hsio/hdmi blk ctrl
  soc: imx: add icc paths for i.MX8MP media blk ctrl
  dt-bindings: arm: imx: update fsl.yaml for imx8dxl
  dt-bindings: firmware: add missing resource IDs for imx8dxl
  dt-bindings: arm: Add i.MX8M Mini Gateworks GW7904 board
  dt-bindings: soc: add i.MX93 mediamix blk ctrl
  dt-bindings: soc: add i.MX93 SRC
  dt-bindings: mfd: syscon: Add i.MX93 blk ctrl system registers
  dt-bindings: arm: fsl: Add MSC SM2S-IMX8PLUS SoM and SM2-MB-EP1 Carrier
  dt-bindings: arm: fsl: Add Kontron BL i.MX8MM OSM-S board
  dt-bindings: arm: fsl: Rename compatibles for Kontron i.MX8MM SoM/board
  dt-bindings: soc: imx: add i.MX8MP vpu blk ctrl
  dt-bindings: soc: imx: add interconnect property for i.MX8MM vpu blk ctrl
  dt-bindings: soc: imx: drop minItems for i.MX8MM vpu blk ctrl
  ...

Link: https://lore.kernel.org/r/20220918092806.2152700-2-shawnguo@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2022-09-23 17:34:19 +02:00
commit b97e1e2faa
19 changed files with 1174 additions and 62 deletions

View File

@ -554,8 +554,7 @@ properties:
- engicam,imx6ul-isiot # Engicam Is.IoT MX6UL eMMC/NAND Starter kit
- fsl,imx6ul-14x14-evk # i.MX6 UltraLite 14x14 EVK Board
- karo,imx6ul-tx6ul # Ka-Ro electronics TXUL-0010 Module
- kontron,imx6ul-n6310-som # Kontron N6310 SOM
- kontron,imx6ul-n6311-som # Kontron N6311 SOM
- kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- prt,prti6g # Protonic PRTI6G Board
- technexion,imx6ul-pico-dwarf # TechNexion i.MX6UL Pico-Dwarf
- technexion,imx6ul-pico-hobbit # TechNexion i.MX6UL Pico-Hobbit
@ -591,23 +590,17 @@ properties:
- const: phytec,imx6ul-pcl063 # PHYTEC phyCORE-i.MX 6UL
- const: fsl,imx6ul
- description: Kontron N6310 S Board
- description: Kontron BL i.MX6UL (N631X S) Board
items:
- const: kontron,imx6ul-n6310-s
- const: kontron,imx6ul-n6310-som
- const: kontron,bl-imx6ul # Kontron BL i.MX6UL Carrier Board
- const: kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- const: fsl,imx6ul
- description: Kontron N6311 S Board
- description: Kontron BL i.MX6UL 43 (N631X S 43) Board
items:
- const: kontron,imx6ul-n6311-s
- const: kontron,imx6ul-n6311-som
- const: fsl,imx6ul
- description: Kontron N6310 S 43 Board
items:
- const: kontron,imx6ul-n6310-s-43
- const: kontron,imx6ul-n6310-s
- const: kontron,imx6ul-n6310-som
- const: kontron,bl-imx6ul-43 # Kontron BL i.MX6UL Carrier Board with 4.3" Display
- const: kontron,bl-imx6ul # Kontron BL i.MX6UL Carrier Board
- const: kontron,sl-imx6ul # Kontron SL i.MX6UL SoM
- const: fsl,imx6ul
- description: TQ-Systems TQMa6UL1 SoM on MBa6ULx board
@ -637,7 +630,7 @@ properties:
- enum:
- fsl,imx6ull-14x14-evk # i.MX6 UltraLiteLite 14x14 EVK Board
- joz,jozacp # JOZ Access Point
- kontron,imx6ull-n6411-som # Kontron N6411 SOM
- kontron,sl-imx6ull # Kontron SL i.MX6ULL SoM
- myir,imx6ull-mys-6ulx-eval # MYiR Tech iMX6ULL Evaluation Board
- toradex,colibri-imx6ull # Colibri iMX6ULL Modules
- toradex,colibri-imx6ull-emmc # Colibri iMX6ULL 1GB (eMMC) Module
@ -698,10 +691,10 @@ properties:
- const: toradex,colibri-imx6ull-wifi # Colibri iMX6ULL Wi-Fi / BT Module
- const: fsl,imx6ull
- description: Kontron N6411 S Board
- description: Kontron BL i.MX6ULL (N6411 S) Board
items:
- const: kontron,imx6ull-n6411-s
- const: kontron,imx6ull-n6411-som
- const: kontron,bl-imx6ull # Kontron BL i.MX6ULL Carrier Board
- const: kontron,sl-imx6ull # Kontron SL i.MX6ULL SoM
- const: fsl,imx6ull
- description: TQ Systems TQMa6ULLx SoM on MBa6ULx board
@ -825,13 +818,15 @@ properties:
- emtrion,emcon-mx8mm-avari # emCON-MX8MM SoM on Avari Base
- fsl,imx8mm-ddr4-evk # i.MX8MM DDR4 EVK Board
- fsl,imx8mm-evk # i.MX8MM EVK Board
- gateworks,imx8mm-gw7904
- gw,imx8mm-gw71xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw72xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw73xx-0x # i.MX8MM Gateworks Development Kit
- gw,imx8mm-gw7901 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7902 # i.MX8MM Gateworks Board
- gw,imx8mm-gw7903 # i.MX8MM Gateworks Board
- kontron,imx8mm-n801x-som # i.MX8MM Kontron SL (N801X) SOM
- kontron,imx8mm-sl # i.MX8MM Kontron SL (N801X) SOM
- kontron,imx8mm-osm-s # i.MX8MM Kontron OSM-S (N802X) SOM
- menlo,mx8menlo # i.MX8MM Menlo board with Verdin SoM
- toradex,verdin-imx8mm # Verdin iMX8M Mini Modules
- toradex,verdin-imx8mm-nonwifi # Verdin iMX8M Mini Modules without Wi-Fi / BT
@ -850,8 +845,14 @@ properties:
- description: Kontron BL i.MX8MM (N801X S) Board
items:
- const: kontron,imx8mm-n801x-s
- const: kontron,imx8mm-n801x-som
- const: kontron,imx8mm-bl
- const: kontron,imx8mm-sl
- const: fsl,imx8mm
- description: Kontron BL i.MX8MM OSM-S (N802X S) Board
items:
- const: kontron,imx8mm-bl-osm-s
- const: kontron,imx8mm-osm-s
- const: fsl,imx8mm
- description: Toradex Boards with Verdin iMX8M Mini Modules
@ -936,6 +937,13 @@ properties:
- toradex,verdin-imx8mp-wifi # Verdin iMX8M Plus Wi-Fi / BT Modules
- const: fsl,imx8mp
- description: Avnet (MSC Branded) Boards with SM2S i.MX8M Plus Modules
items:
- const: avnet,sm2s-imx8mp-14N0600E-ep1 # SM2S-IMX8PLUS-14N0600E on SM2-MB-EP1 Carrier Board
- const: avnet,sm2s-imx8mp-14N0600E # 14N0600E variant of SM2S-IMX8PLUS SoM
- const: avnet,sm2s-imx8mp # SM2S-IMX8PLUS SoM
- const: fsl,imx8mp
- description: Engicam i.Core MX8M Plus SoM based boards
items:
- enum:
@ -1034,6 +1042,12 @@ properties:
- toradex,colibri-imx8x # Colibri iMX8X Modules
- const: fsl,imx8qxp
- description: i.MX8DXL based Boards
items:
- enum:
- fsl,imx8dxl-evk # i.MX8DXL EVK Board
- const: fsl,imx8dxl
- description: i.MX8QXP Boards with Toradex Coilbri iMX8X Modules
items:
- enum:

View File

@ -40,6 +40,8 @@ properties:
- allwinner,sun50i-a64-system-controller
- brcm,cru-clkset
- freecom,fsg-cs2-system-controller
- fsl,imx93-aonmix-ns-syscfg
- fsl,imx93-wakeupmix-syscfg
- hisilicon,dsa-subctrl
- hisilicon,hi6220-sramctrl
- hisilicon,pcie-sas-subctrl

View File

@ -27,25 +27,22 @@ properties:
const: 1
power-domains:
minItems: 4
maxItems: 4
power-domain-names:
items:
- const: bus
- const: g1
- const: g2
- const: h1
maxItems: 4
clocks:
minItems: 3
maxItems: 3
clock-names:
items:
- const: g1
- const: g2
- const: h1
maxItems: 3
interconnects:
maxItems: 3
interconnect-names:
maxItems: 3
required:
- compatible
@ -55,6 +52,97 @@ required:
- clocks
- clock-names
allOf:
- if:
properties:
compatible:
contains:
const: fsl,imx8mm-vpu-blk-ctrl
then:
properties:
power-domains:
items:
- description: bus power domain
- description: G1 decoder power domain
- description: G2 decoder power domain
- description: H1 encoder power domain
power-domain-names:
items:
- const: bus
- const: g1
- const: g2
- const: h1
clocks:
items:
- description: G1 decoder clk
- description: G2 decoder clk
- description: H1 encoder clk
clock-names:
items:
- const: g1
- const: g2
- const: h1
interconnects:
items:
- description: G1 decoder interconnect
- description: G2 decoder interconnect
- description: H1 encoder power domain
interconnect-names:
items:
- const: g1
- const: g2
- const: h1
- if:
properties:
compatible:
contains:
const: fsl,imx8mp-vpu-blk-ctrl
then:
properties:
power-domains:
items:
- description: bus power domain
- description: G1 decoder power domain
- description: G2 decoder power domain
- description: VC8000E encoder power domain
power-domain-names:
items:
- const: bus
- const: g1
- const: g2
- const: vc8000e
clocks:
items:
- description: G1 decoder clk
- description: G2 decoder clk
- description: VC8000E encoder clk
clock-names:
items:
- const: g1
- const: g2
- const: vc8000e
interconnects:
items:
- description: G1 decoder interconnect
- description: G2 decoder interconnect
- description: VC8000E encoder interconnect
interconnect-names:
items:
- const: g1
- const: g2
- const: vc8000e
additionalProperties: false
examples:

View File

@ -52,6 +52,15 @@ properties:
- const: ref_266m
- const: ref_24m
interconnects:
maxItems: 3
interconnect-names:
items:
- const: hrv
- const: lcdif-hdmi
- const: hdcp
required:
- compatible
- reg

View File

@ -48,6 +48,16 @@ properties:
- const: usb
- const: pcie
interconnects:
maxItems: 4
interconnect-names:
items:
- const: noc-pcie
- const: usb1
- const: usb2
- const: pcie
required:
- compatible
- reg

View File

@ -64,6 +64,20 @@ properties:
- const: isp
- const: phy
interconnects:
maxItems: 8
interconnect-names:
items:
- const: lcdif-rd
- const: lcdif-wr
- const: isi0
- const: isi1
- const: isi2
- const: isp0
- const: isp1
- const: dwe
required:
- compatible
- reg

View File

@ -0,0 +1,80 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/imx/fsl,imx93-media-blk-ctrl.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX93 Media blk-ctrl
maintainers:
- Peng Fan <peng.fan@nxp.com>
description:
The i.MX93 MEDIAMIX domain contains control and status registers known
as MEDIAMIX Block Control (MEDIAMIX BLK_CTRL). These registers include
clocking, reset, and miscellaneous top-level controls for peripherals
within the MEDIAMIX domain
properties:
compatible:
items:
- const: fsl,imx93-media-blk-ctrl
- const: syscon
reg:
maxItems: 1
'#power-domain-cells':
const: 1
power-domains:
maxItems: 1
clocks:
maxItems: 10
clock-names:
items:
- const: apb
- const: axi
- const: nic
- const: disp
- const: cam
- const: pxp
- const: lcdif
- const: isi
- const: csi
- const: dsi
required:
- compatible
- reg
- power-domains
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx93-clock.h>
#include <dt-bindings/power/fsl,imx93-power.h>
media_blk_ctrl: system-controller@4ac10000 {
compatible = "fsl,imx93-media-blk-ctrl", "syscon";
reg = <0x4ac10000 0x10000>;
power-domains = <&mediamix>;
clocks = <&clk IMX93_CLK_MEDIA_APB>,
<&clk IMX93_CLK_MEDIA_AXI>,
<&clk IMX93_CLK_NIC_MEDIA_GATE>,
<&clk IMX93_CLK_MEDIA_DISP_PIX>,
<&clk IMX93_CLK_CAM_PIX>,
<&clk IMX93_CLK_PXP_GATE>,
<&clk IMX93_CLK_LCDIF_GATE>,
<&clk IMX93_CLK_ISI_GATE>,
<&clk IMX93_CLK_MIPI_CSI_GATE>,
<&clk IMX93_CLK_MIPI_DSI_GATE>;
clock-names = "apb", "axi", "nic", "disp", "cam",
"pxp", "lcdif", "isi", "csi", "dsi";
#power-domain-cells = <1>;
};

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/soc/imx/fsl,imx93-src.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX93 System Reset Controller
maintainers:
- Peng Fan <peng.fan@nxp.com>
description: |
The System Reset Controller (SRC) is responsible for the generation of
all the system reset signals and boot argument latching.
Its main functions are as follows,
- Deals with all global system reset sources from other modules,
and generates global system reset.
- Responsible for power gating of MIXs (Slices) and their memory
low power control.
properties:
compatible:
items:
- const: fsl,imx93-src
- const: syscon
reg:
maxItems: 1
ranges: true
'#address-cells':
const: 1
'#size-cells':
const: 1
patternProperties:
"power-domain@[0-9a-f]+$":
type: object
properties:
compatible:
items:
- const: fsl,imx93-src-slice
'#power-domain-cells':
const: 0
reg:
items:
- description: mix slice register region
- description: mem slice register region
clocks:
description: |
A number of phandles to clocks that need to be enabled
during domain power-up sequencing to ensure reset
propagation into devices located inside this power domain.
minItems: 1
maxItems: 5
required:
- compatible
- '#power-domain-cells'
- reg
required:
- compatible
- reg
- ranges
- '#address-cells'
- '#size-cells'
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx93-clock.h>
system-controller@44460000 {
compatible = "fsl,imx93-src", "syscon";
reg = <0x44460000 0x10000>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
mediamix: power-domain@0 {
compatible = "fsl,imx93-src-slice";
reg = <0x44462400 0x400>, <0x44465800 0x400>;
#power-domain-cells = <0>;
clocks = <&clk IMX93_CLK_MEDIA_AXI>,
<&clk IMX93_CLK_MEDIA_APB>;
};
};

View File

@ -20,4 +20,12 @@ config SOC_IMX8M
support, it will provide the SoC info like SoC family,
ID and revision etc.
config SOC_IMX9
tristate "i.MX9 SoC family support"
depends on ARCH_MXC || COMPILE_TEST
default ARCH_MXC && ARM64
select SOC_BUS
help
If you say yes here, you get support for the NXP i.MX9 family
endmenu

View File

@ -7,3 +7,5 @@ obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o
obj-$(CONFIG_SOC_IMX8M) += imx8m-blk-ctrl.o
obj-$(CONFIG_SOC_IMX8M) += imx8mp-blk-ctrl.o
obj-$(CONFIG_SOC_IMX9) += imx93-src.o imx93-pd.o
obj-$(CONFIG_SOC_IMX9) += imx93-blk-ctrl.o

View File

@ -5,6 +5,7 @@
*/
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@ -37,6 +38,8 @@ struct imx8m_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
const char * const *path_names;
int num_paths;
const char *gpc_name;
u32 rst_mask;
u32 clk_mask;
@ -52,13 +55,16 @@ struct imx8m_blk_ctrl_domain_data {
};
#define DOMAIN_MAX_CLKS 4
#define DOMAIN_MAX_PATHS 4
struct imx8m_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx8m_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
struct device *power_dev;
struct imx8m_blk_ctrl *bc;
int num_paths;
};
struct imx8m_blk_ctrl_data {
@ -117,6 +123,10 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
if (data->mipi_phy_rst_mask)
regmap_set_bits(bc->regmap, BLK_MIPI_RESET_DIV, data->mipi_phy_rst_mask);
ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
if (ret)
dev_err(bc->dev, "failed to set icc bw\n");
/* disable upstream clocks */
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
@ -152,19 +162,6 @@ static int imx8m_blk_ctrl_power_off(struct generic_pm_domain *genpd)
return 0;
}
static struct generic_pm_domain *
imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
{
struct genpd_onecell_data *onecell_data = data;
unsigned int index = args->args[0];
if (args->args_count != 1 ||
index >= onecell_data->num_domains)
return ERR_PTR(-EINVAL);
return onecell_data->domains[index];
}
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
@ -206,7 +203,6 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->onecell_data.num_domains = bc_data->num_domains;
bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
bc->onecell_data.domains =
devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
@ -224,10 +220,29 @@ static int imx8m_blk_ctrl_probe(struct platform_device *pdev)
int j;
domain->data = data;
domain->num_paths = data->num_paths;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
for (j = 0; j < data->num_paths; j++) {
domain->paths[j].name = data->path_names[j];
/* Fake value for now, just let ICC could configure NoC mode/priority */
domain->paths[j].avg_bw = 1;
domain->paths[j].peak_bw = 1;
}
ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
if (ret) {
if (ret != -EPROBE_DEFER) {
dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
domain->num_paths = 0;
} else {
dev_err_probe(dev, ret, "failed to get noc entries\n");
goto cleanup_pds;
}
}
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");
@ -455,6 +470,46 @@ static const struct imx8m_blk_ctrl_data imx8mm_vpu_blk_ctl_dev_data = {
.num_domains = ARRAY_SIZE(imx8mm_vpu_blk_ctl_domain_data),
};
static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[] = {
[IMX8MP_VPUBLK_PD_G1] = {
.name = "vpublk-g1",
.clk_names = (const char *[]){ "g1", },
.num_clks = 1,
.gpc_name = "g1",
.rst_mask = BIT(1),
.clk_mask = BIT(1),
.path_names = (const char *[]){"g1"},
.num_paths = 1,
},
[IMX8MP_VPUBLK_PD_G2] = {
.name = "vpublk-g2",
.clk_names = (const char *[]){ "g2", },
.num_clks = 1,
.gpc_name = "g2",
.rst_mask = BIT(0),
.clk_mask = BIT(0),
.path_names = (const char *[]){"g2"},
.num_paths = 1,
},
[IMX8MP_VPUBLK_PD_VC8000E] = {
.name = "vpublk-vc8000e",
.clk_names = (const char *[]){ "vc8000e", },
.num_clks = 1,
.gpc_name = "vc8000e",
.rst_mask = BIT(2),
.clk_mask = BIT(2),
.path_names = (const char *[]){"vc8000e"},
.num_paths = 1,
},
};
static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
.max_reg = 0x18,
.power_notifier_fn = imx8mm_vpu_power_notifier,
.domains = imx8mp_vpu_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
};
static int imx8mm_disp_power_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
@ -650,6 +705,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "lcdif1",
.rst_mask = BIT(4) | BIT(5) | BIT(23),
.clk_mask = BIT(4) | BIT(5) | BIT(23),
.path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_ISI] = {
.name = "mediablk-isi",
@ -658,6 +715,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "isi",
.rst_mask = BIT(6) | BIT(7),
.clk_mask = BIT(6) | BIT(7),
.path_names = (const char *[]){"isi0", "isi1", "isi2"},
.num_paths = 3,
},
[IMX8MP_MEDIABLK_PD_MIPI_CSI2_2] = {
.name = "mediablk-mipi-csi2-2",
@ -675,6 +734,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "lcdif2",
.rst_mask = BIT(11) | BIT(12) | BIT(24),
.clk_mask = BIT(11) | BIT(12) | BIT(24),
.path_names = (const char *[]){"lcdif-rd", "lcdif-wr"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_ISP] = {
.name = "mediablk-isp",
@ -683,6 +744,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "isp",
.rst_mask = BIT(16) | BIT(17) | BIT(18),
.clk_mask = BIT(16) | BIT(17) | BIT(18),
.path_names = (const char *[]){"isp0", "isp1"},
.num_paths = 2,
},
[IMX8MP_MEDIABLK_PD_DWE] = {
.name = "mediablk-dwe",
@ -691,6 +754,8 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_media_blk_ctl_domain_data[
.gpc_name = "dwe",
.rst_mask = BIT(19) | BIT(20) | BIT(21),
.clk_mask = BIT(19) | BIT(20) | BIT(21),
.path_names = (const char *[]){"dwe"},
.num_paths = 1,
},
[IMX8MP_MEDIABLK_PD_MIPI_DSI_2] = {
.name = "mediablk-mipi-dsi-2",
@ -788,6 +853,9 @@ static const struct of_device_id imx8m_blk_ctrl_of_match[] = {
}, {
.compatible = "fsl,imx8mq-vpu-blk-ctrl",
.data = &imx8mq_vpu_blk_ctl_dev_data
}, {
.compatible = "fsl,imx8mp-vpu-blk-ctrl",
.data = &imx8mp_vpu_blk_ctl_dev_data
}, {
/* Sentinel */
}

View File

@ -6,6 +6,7 @@
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@ -18,6 +19,8 @@
#define GPR_REG0 0x0
#define PCIE_CLOCK_MODULE_EN BIT(0)
#define USB_CLOCK_MODULE_EN BIT(1)
#define PCIE_PHY_APB_RST BIT(4)
#define PCIE_PHY_INIT_RST BIT(5)
struct imx8mp_blk_ctrl_domain;
@ -36,17 +39,22 @@ struct imx8mp_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
const char * const *path_names;
int num_paths;
const char *gpc_name;
};
#define DOMAIN_MAX_CLKS 2
#define DOMAIN_MAX_PATHS 3
struct imx8mp_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx8mp_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct icc_bulk_data paths[DOMAIN_MAX_PATHS];
struct device *power_dev;
struct imx8mp_blk_ctrl *bc;
int num_paths;
int id;
};
@ -75,6 +83,10 @@ static void imx8mp_hsio_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
case IMX8MP_HSIOBLK_PD_PCIE:
regmap_set_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
break;
case IMX8MP_HSIOBLK_PD_PCIE_PHY:
regmap_set_bits(bc->regmap, GPR_REG0,
PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
break;
default:
break;
}
@ -90,6 +102,10 @@ static void imx8mp_hsio_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
case IMX8MP_HSIOBLK_PD_PCIE:
regmap_clear_bits(bc->regmap, GPR_REG0, PCIE_CLOCK_MODULE_EN);
break;
case IMX8MP_HSIOBLK_PD_PCIE_PHY:
regmap_clear_bits(bc->regmap, GPR_REG0,
PCIE_PHY_APB_RST | PCIE_PHY_INIT_RST);
break;
default:
break;
}
@ -144,6 +160,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
.clk_names = (const char *[]){ "usb" },
.num_clks = 1,
.gpc_name = "usb",
.path_names = (const char *[]){"usb1", "usb2"},
.num_paths = 2,
},
[IMX8MP_HSIOBLK_PD_USB_PHY1] = {
.name = "hsioblk-usb-phy1",
@ -158,6 +176,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hsio_domain_data[] = {
.clk_names = (const char *[]){ "pcie" },
.num_clks = 1,
.gpc_name = "pcie",
.path_names = (const char *[]){"noc-pcie", "pcie"},
.num_paths = 2,
},
[IMX8MP_HSIOBLK_PD_PCIE_PHY] = {
.name = "hsioblk-pcie-phy",
@ -225,6 +245,13 @@ static void imx8mp_hdmi_blk_ctrl_power_on(struct imx8mp_blk_ctrl *bc,
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_TX_CONTROL0, BIT(3));
break;
case IMX8MP_HDMIBLK_PD_HDCP:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_set_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
regmap_set_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
break;
default:
break;
}
@ -273,6 +300,13 @@ static void imx8mp_hdmi_blk_ctrl_power_off(struct imx8mp_blk_ctrl *bc,
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(12));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(22) | BIT(24));
break;
case IMX8MP_HDMIBLK_PD_HDCP:
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL0, BIT(11));
break;
case IMX8MP_HDMIBLK_PD_HRV:
regmap_clear_bits(bc->regmap, HDMI_RTX_RESET_CTL0, BIT(15));
regmap_clear_bits(bc->regmap, HDMI_RTX_CLK_CTL1, BIT(3) | BIT(4) | BIT(5));
break;
default:
break;
}
@ -322,6 +356,8 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "lcdif",
.path_names = (const char *[]){"lcdif-hdmi"},
.num_paths = 1,
},
[IMX8MP_HDMIBLK_PD_PAI] = {
.name = "hdmiblk-pai",
@ -353,6 +389,22 @@ static const struct imx8mp_blk_ctrl_domain_data imx8mp_hdmi_domain_data[] = {
.num_clks = 2,
.gpc_name = "hdmi-tx-phy",
},
[IMX8MP_HDMIBLK_PD_HRV] = {
.name = "hdmiblk-hrv",
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "hrv",
.path_names = (const char *[]){"hrv"},
.num_paths = 1,
},
[IMX8MP_HDMIBLK_PD_HDCP] = {
.name = "hdmiblk-hdcp",
.clk_names = (const char *[]){ "axi", "apb" },
.num_clks = 2,
.gpc_name = "hdcp",
.path_names = (const char *[]){"hdcp"},
.num_paths = 1,
},
};
static const struct imx8mp_blk_ctrl_data imx8mp_hdmi_blk_ctl_dev_data = {
@ -395,6 +447,10 @@ static int imx8mp_blk_ctrl_power_on(struct generic_pm_domain *genpd)
goto clk_disable;
}
ret = icc_bulk_set_bw(domain->num_paths, domain->paths);
if (ret)
dev_err(bc->dev, "failed to set icc bw\n");
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
return 0;
@ -434,19 +490,6 @@ static int imx8mp_blk_ctrl_power_off(struct generic_pm_domain *genpd)
return 0;
}
static struct generic_pm_domain *
imx8m_blk_ctrl_xlate(struct of_phandle_args *args, void *data)
{
struct genpd_onecell_data *onecell_data = data;
unsigned int index = args->args[0];
if (args->args_count != 1 ||
index >= onecell_data->num_domains)
return ERR_PTR(-EINVAL);
return onecell_data->domains[index];
}
static struct lock_class_key blk_ctrl_genpd_lock_class;
static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
@ -489,7 +532,6 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
return -ENOMEM;
bc->onecell_data.num_domains = num_domains;
bc->onecell_data.xlate = imx8m_blk_ctrl_xlate;
bc->onecell_data.domains =
devm_kcalloc(dev, num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
@ -510,10 +552,29 @@ static int imx8mp_blk_ctrl_probe(struct platform_device *pdev)
int j;
domain->data = data;
domain->num_paths = data->num_paths;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
for (j = 0; j < data->num_paths; j++) {
domain->paths[j].name = data->path_names[j];
/* Fake value for now, just let ICC could configure NoC mode/priority */
domain->paths[j].avg_bw = 1;
domain->paths[j].peak_bw = 1;
}
ret = devm_of_icc_bulk_get(dev, data->num_paths, domain->paths);
if (ret) {
if (ret != -EPROBE_DEFER) {
dev_warn_once(dev, "Could not get interconnect paths, NoC will stay unconfigured!\n");
domain->num_paths = 0;
} else {
dev_err_probe(dev, ret, "failed to get noc entries\n");
goto cleanup_pds;
}
}
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");

View File

@ -0,0 +1,436 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP, Peng Fan <peng.fan@nxp.com>
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <dt-bindings/power/fsl,imx93-power.h>
#define BLK_SFT_RSTN 0x0
#define BLK_CLK_EN 0x4
#define BLK_MAX_CLKS 4
#define DOMAIN_MAX_CLKS 4
#define LCDIF_QOS_REG 0xC
#define LCDIF_DEFAULT_QOS_OFF 12
#define LCDIF_CFG_QOS_OFF 8
#define PXP_QOS_REG 0x10
#define PXP_R_DEFAULT_QOS_OFF 28
#define PXP_R_CFG_QOS_OFF 24
#define PXP_W_DEFAULT_QOS_OFF 20
#define PXP_W_CFG_QOS_OFF 16
#define ISI_CACHE_REG 0x14
#define ISI_QOS_REG 0x1C
#define ISI_V_DEFAULT_QOS_OFF 28
#define ISI_V_CFG_QOS_OFF 24
#define ISI_U_DEFAULT_QOS_OFF 20
#define ISI_U_CFG_QOS_OFF 16
#define ISI_Y_R_DEFAULT_QOS_OFF 12
#define ISI_Y_R_CFG_QOS_OFF 8
#define ISI_Y_W_DEFAULT_QOS_OFF 4
#define ISI_Y_W_CFG_QOS_OFF 0
#define PRIO_MASK 0xF
#define PRIO(X) (X)
struct imx93_blk_ctrl_domain;
struct imx93_blk_ctrl {
struct device *dev;
struct regmap *regmap;
int num_clks;
struct clk_bulk_data clks[BLK_MAX_CLKS];
struct imx93_blk_ctrl_domain *domains;
struct genpd_onecell_data onecell_data;
};
#define DOMAIN_MAX_QOS 4
struct imx93_blk_ctrl_qos {
u32 reg;
u32 cfg_off;
u32 default_prio;
u32 cfg_prio;
};
struct imx93_blk_ctrl_domain_data {
const char *name;
const char * const *clk_names;
int num_clks;
u32 rst_mask;
u32 clk_mask;
int num_qos;
struct imx93_blk_ctrl_qos qos[DOMAIN_MAX_QOS];
};
struct imx93_blk_ctrl_domain {
struct generic_pm_domain genpd;
const struct imx93_blk_ctrl_domain_data *data;
struct clk_bulk_data clks[DOMAIN_MAX_CLKS];
struct imx93_blk_ctrl *bc;
};
struct imx93_blk_ctrl_data {
const struct imx93_blk_ctrl_domain_data *domains;
int num_domains;
const char * const *clk_names;
int num_clks;
const struct regmap_access_table *reg_access_table;
};
static inline struct imx93_blk_ctrl_domain *
to_imx93_blk_ctrl_domain(struct generic_pm_domain *genpd)
{
return container_of(genpd, struct imx93_blk_ctrl_domain, genpd);
}
static int imx93_blk_ctrl_set_qos(struct imx93_blk_ctrl_domain *domain)
{
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
const struct imx93_blk_ctrl_qos *qos;
u32 val, mask;
int i;
for (i = 0; i < data->num_qos; i++) {
qos = &data->qos[i];
mask = PRIO_MASK << qos->cfg_off;
mask |= PRIO_MASK << (qos->cfg_off + 4);
val = qos->cfg_prio << qos->cfg_off;
val |= qos->default_prio << (qos->cfg_off + 4);
regmap_write_bits(bc->regmap, qos->reg, mask, val);
dev_dbg(bc->dev, "data->qos[i].reg 0x%x 0x%x\n", qos->reg, val);
}
return 0;
}
static int imx93_blk_ctrl_power_on(struct generic_pm_domain *genpd)
{
struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
int ret;
ret = clk_bulk_prepare_enable(bc->num_clks, bc->clks);
if (ret) {
dev_err(bc->dev, "failed to enable bus clocks\n");
return ret;
}
ret = clk_bulk_prepare_enable(data->num_clks, domain->clks);
if (ret) {
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
dev_err(bc->dev, "failed to enable clocks\n");
return ret;
}
ret = pm_runtime_get_sync(bc->dev);
if (ret < 0) {
pm_runtime_put_noidle(bc->dev);
dev_err(bc->dev, "failed to power up domain\n");
goto disable_clk;
}
/* ungate clk */
regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* release reset */
regmap_set_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
dev_dbg(bc->dev, "pd_on: name: %s\n", genpd->name);
return imx93_blk_ctrl_set_qos(domain);
disable_clk:
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
return ret;
}
static int imx93_blk_ctrl_power_off(struct generic_pm_domain *genpd)
{
struct imx93_blk_ctrl_domain *domain = to_imx93_blk_ctrl_domain(genpd);
const struct imx93_blk_ctrl_domain_data *data = domain->data;
struct imx93_blk_ctrl *bc = domain->bc;
dev_dbg(bc->dev, "pd_off: name: %s\n", genpd->name);
regmap_clear_bits(bc->regmap, BLK_SFT_RSTN, data->rst_mask);
regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
pm_runtime_put(bc->dev);
clk_bulk_disable_unprepare(data->num_clks, domain->clks);
clk_bulk_disable_unprepare(bc->num_clks, bc->clks);
return 0;
}
static int imx93_blk_ctrl_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct imx93_blk_ctrl_data *bc_data = of_device_get_match_data(dev);
struct imx93_blk_ctrl *bc;
void __iomem *base;
int i, ret;
struct regmap_config regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.rd_table = bc_data->reg_access_table,
.wr_table = bc_data->reg_access_table,
.max_register = SZ_4K,
};
bc = devm_kzalloc(dev, sizeof(*bc), GFP_KERNEL);
if (!bc)
return -ENOMEM;
bc->dev = dev;
base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(base))
return PTR_ERR(base);
bc->regmap = devm_regmap_init_mmio(dev, base, &regmap_config);
if (IS_ERR(bc->regmap))
return dev_err_probe(dev, PTR_ERR(bc->regmap),
"failed to init regmap\n");
bc->domains = devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct imx93_blk_ctrl_domain),
GFP_KERNEL);
if (!bc->domains)
return -ENOMEM;
bc->onecell_data.num_domains = bc_data->num_domains;
bc->onecell_data.domains =
devm_kcalloc(dev, bc_data->num_domains,
sizeof(struct generic_pm_domain *), GFP_KERNEL);
if (!bc->onecell_data.domains)
return -ENOMEM;
for (i = 0; i < bc_data->num_clks; i++)
bc->clks[i].id = bc_data->clk_names[i];
bc->num_clks = bc_data->num_clks;
ret = devm_clk_bulk_get(dev, bc->num_clks, bc->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get bus clock\n");
return ret;
}
for (i = 0; i < bc_data->num_domains; i++) {
const struct imx93_blk_ctrl_domain_data *data = &bc_data->domains[i];
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
int j;
domain->data = data;
for (j = 0; j < data->num_clks; j++)
domain->clks[j].id = data->clk_names[j];
ret = devm_clk_bulk_get(dev, data->num_clks, domain->clks);
if (ret) {
dev_err_probe(dev, ret, "failed to get clock\n");
goto cleanup_pds;
}
domain->genpd.name = data->name;
domain->genpd.power_on = imx93_blk_ctrl_power_on;
domain->genpd.power_off = imx93_blk_ctrl_power_off;
domain->bc = bc;
ret = pm_genpd_init(&domain->genpd, NULL, true);
if (ret) {
dev_err_probe(dev, ret, "failed to init power domain\n");
goto cleanup_pds;
}
bc->onecell_data.domains[i] = &domain->genpd;
}
pm_runtime_enable(dev);
ret = of_genpd_add_provider_onecell(dev->of_node, &bc->onecell_data);
if (ret) {
dev_err_probe(dev, ret, "failed to add power domain provider\n");
goto cleanup_pds;
}
dev_set_drvdata(dev, bc);
return 0;
cleanup_pds:
for (i--; i >= 0; i--)
pm_genpd_remove(&bc->domains[i].genpd);
return ret;
}
static int imx93_blk_ctrl_remove(struct platform_device *pdev)
{
struct imx93_blk_ctrl *bc = dev_get_drvdata(&pdev->dev);
int i;
of_genpd_del_provider(pdev->dev.of_node);
for (i = 0; bc->onecell_data.num_domains; i++) {
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
pm_genpd_remove(&domain->genpd);
}
return 0;
}
static const struct imx93_blk_ctrl_domain_data imx93_media_blk_ctl_domain_data[] = {
[IMX93_MEDIABLK_PD_MIPI_DSI] = {
.name = "mediablk-mipi-dsi",
.clk_names = (const char *[]){ "dsi" },
.num_clks = 1,
.rst_mask = BIT(11) | BIT(12),
.clk_mask = BIT(11) | BIT(12),
},
[IMX93_MEDIABLK_PD_MIPI_CSI] = {
.name = "mediablk-mipi-csi",
.clk_names = (const char *[]){ "cam", "csi" },
.num_clks = 2,
.rst_mask = BIT(9) | BIT(10),
.clk_mask = BIT(9) | BIT(10),
},
[IMX93_MEDIABLK_PD_PXP] = {
.name = "mediablk-pxp",
.clk_names = (const char *[]){ "pxp" },
.num_clks = 1,
.rst_mask = BIT(7) | BIT(8),
.clk_mask = BIT(7) | BIT(8),
.num_qos = 2,
.qos = {
{
.reg = PXP_QOS_REG,
.cfg_off = PXP_R_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(6),
}, {
.reg = PXP_QOS_REG,
.cfg_off = PXP_W_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(6),
}
}
},
[IMX93_MEDIABLK_PD_LCDIF] = {
.name = "mediablk-lcdif",
.clk_names = (const char *[]){ "disp", "lcdif" },
.num_clks = 2,
.rst_mask = BIT(4) | BIT(5) | BIT(6),
.clk_mask = BIT(4) | BIT(5) | BIT(6),
.num_qos = 1,
.qos = {
{
.reg = LCDIF_QOS_REG,
.cfg_off = LCDIF_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}
}
},
[IMX93_MEDIABLK_PD_ISI] = {
.name = "mediablk-isi",
.clk_names = (const char *[]){ "isi" },
.num_clks = 1,
.rst_mask = BIT(2) | BIT(3),
.clk_mask = BIT(2) | BIT(3),
.num_qos = 4,
.qos = {
{
.reg = ISI_QOS_REG,
.cfg_off = ISI_Y_W_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_Y_R_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_U_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}, {
.reg = ISI_QOS_REG,
.cfg_off = ISI_V_CFG_QOS_OFF,
.default_prio = PRIO(3),
.cfg_prio = PRIO(7),
}
}
},
};
static const struct regmap_range imx93_media_blk_ctl_yes_ranges[] = {
regmap_reg_range(BLK_SFT_RSTN, BLK_CLK_EN),
regmap_reg_range(LCDIF_QOS_REG, ISI_CACHE_REG),
regmap_reg_range(ISI_QOS_REG, ISI_QOS_REG),
};
static const struct regmap_access_table imx93_media_blk_ctl_access_table = {
.yes_ranges = imx93_media_blk_ctl_yes_ranges,
.n_yes_ranges = ARRAY_SIZE(imx93_media_blk_ctl_yes_ranges),
};
static const struct imx93_blk_ctrl_data imx93_media_blk_ctl_dev_data = {
.domains = imx93_media_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx93_media_blk_ctl_domain_data),
.clk_names = (const char *[]){ "axi", "apb", "nic", },
.num_clks = 3,
.reg_access_table = &imx93_media_blk_ctl_access_table,
};
static const struct of_device_id imx93_blk_ctrl_of_match[] = {
{
.compatible = "fsl,imx93-media-blk-ctrl",
.data = &imx93_media_blk_ctl_dev_data
}, {
/* Sentinel */
}
};
MODULE_DEVICE_TABLE(of, imx93_blk_ctrl_of_match);
static struct platform_driver imx93_blk_ctrl_driver = {
.probe = imx93_blk_ctrl_probe,
.remove = imx93_blk_ctrl_remove,
.driver = {
.name = "imx93-blk-ctrl",
.of_match_table = imx93_blk_ctrl_of_match,
},
};
module_platform_driver(imx93_blk_ctrl_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("i.MX93 BLK CTRL driver");
MODULE_LICENSE("GPL");

164
drivers/soc/imx/imx93-pd.c Normal file
View File

@ -0,0 +1,164 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/of_device.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#define MIX_SLICE_SW_CTRL_OFF 0x20
#define SLICE_SW_CTRL_PSW_CTRL_OFF_MASK BIT(4)
#define SLICE_SW_CTRL_PDN_SOFT_MASK BIT(31)
#define MIX_FUNC_STAT_OFF 0xB4
#define FUNC_STAT_PSW_STAT_MASK BIT(0)
#define FUNC_STAT_RST_STAT_MASK BIT(2)
#define FUNC_STAT_ISO_STAT_MASK BIT(4)
struct imx93_power_domain {
struct generic_pm_domain genpd;
struct device *dev;
void __iomem *addr;
struct clk_bulk_data *clks;
int num_clks;
bool init_off;
};
#define to_imx93_pd(_genpd) container_of(_genpd, struct imx93_power_domain, genpd)
static int imx93_pd_on(struct generic_pm_domain *genpd)
{
struct imx93_power_domain *domain = to_imx93_pd(genpd);
void __iomem *addr = domain->addr;
u32 val;
int ret;
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
if (ret) {
dev_err(domain->dev, "failed to enable clocks for domain: %s\n", genpd->name);
return ret;
}
val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
val &= ~SLICE_SW_CTRL_PDN_SOFT_MASK;
writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
!(val & FUNC_STAT_ISO_STAT_MASK), 1, 10000);
if (ret) {
dev_err(domain->dev, "pd_on timeout: name: %s, stat: %x\n", genpd->name, val);
return ret;
}
return 0;
}
static int imx93_pd_off(struct generic_pm_domain *genpd)
{
struct imx93_power_domain *domain = to_imx93_pd(genpd);
void __iomem *addr = domain->addr;
int ret;
u32 val;
/* Power off MIX */
val = readl(addr + MIX_SLICE_SW_CTRL_OFF);
val |= SLICE_SW_CTRL_PDN_SOFT_MASK;
writel(val, addr + MIX_SLICE_SW_CTRL_OFF);
ret = readl_poll_timeout(addr + MIX_FUNC_STAT_OFF, val,
val & FUNC_STAT_PSW_STAT_MASK, 1, 1000);
if (ret) {
dev_err(domain->dev, "pd_off timeout: name: %s, stat: %x\n", genpd->name, val);
return ret;
}
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
return 0;
};
static int imx93_pd_remove(struct platform_device *pdev)
{
struct imx93_power_domain *domain = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
if (!domain->init_off)
clk_bulk_disable_unprepare(domain->num_clks, domain->clks);
of_genpd_del_provider(np);
pm_genpd_remove(&domain->genpd);
return 0;
}
static int imx93_pd_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct imx93_power_domain *domain;
int ret;
domain = devm_kzalloc(dev, sizeof(*domain), GFP_KERNEL);
if (!domain)
return -ENOMEM;
domain->addr = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(domain->addr))
return PTR_ERR(domain->addr);
domain->num_clks = devm_clk_bulk_get_all(dev, &domain->clks);
if (domain->num_clks < 0)
return dev_err_probe(dev, domain->num_clks, "Failed to get domain's clocks\n");
domain->genpd.name = dev_name(dev);
domain->genpd.power_off = imx93_pd_off;
domain->genpd.power_on = imx93_pd_on;
domain->dev = dev;
domain->init_off = readl(domain->addr + MIX_FUNC_STAT_OFF) & FUNC_STAT_ISO_STAT_MASK;
/* Just to sync the status of hardware */
if (!domain->init_off) {
ret = clk_bulk_prepare_enable(domain->num_clks, domain->clks);
if (ret) {
dev_err(domain->dev, "failed to enable clocks for domain: %s\n",
domain->genpd.name);
return ret;
}
}
ret = pm_genpd_init(&domain->genpd, NULL, domain->init_off);
if (ret)
return ret;
platform_set_drvdata(pdev, domain);
return of_genpd_add_provider_simple(np, &domain->genpd);
}
static const struct of_device_id imx93_pd_ids[] = {
{ .compatible = "fsl,imx93-src-slice" },
{ }
};
MODULE_DEVICE_TABLE(of, imx93_pd_ids);
static struct platform_driver imx93_power_domain_driver = {
.driver = {
.name = "imx93_power_domain",
.owner = THIS_MODULE,
.of_match_table = imx93_pd_ids,
},
.probe = imx93_pd_probe,
.remove = imx93_pd_remove,
};
module_platform_driver(imx93_power_domain_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX93 power domain driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2022 NXP
*/
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
static int imx93_src_probe(struct platform_device *pdev)
{
return devm_of_platform_populate(&pdev->dev);
}
static const struct of_device_id imx93_src_ids[] = {
{ .compatible = "fsl,imx93-src" },
{ }
};
MODULE_DEVICE_TABLE(of, imx93_src_ids);
static struct platform_driver imx93_src_driver = {
.driver = {
.name = "imx93_src",
.owner = THIS_MODULE,
.of_match_table = imx93_src_ids,
},
.probe = imx93_src_probe,
};
module_platform_driver(imx93_src_driver);
MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
MODULE_DESCRIPTION("NXP i.MX93 src driver");
MODULE_LICENSE("GPL");

View File

@ -281,7 +281,6 @@
#define IMX8MM_CLK_CLKOUT2_DIV 256
#define IMX8MM_CLK_CLKOUT2 257
#define IMX8MM_CLK_END 258
#endif

View File

@ -37,10 +37,14 @@
#define IMX_SC_R_DC_0_BLIT2 21
#define IMX_SC_R_DC_0_BLIT_OUT 22
#define IMX_SC_R_PERF 23
#define IMX_SC_R_USB_1_PHY 24
#define IMX_SC_R_DC_0_WARP 25
#define IMX_SC_R_V2X_MU_0 26
#define IMX_SC_R_V2X_MU_1 27
#define IMX_SC_R_DC_0_VIDEO0 28
#define IMX_SC_R_DC_0_VIDEO1 29
#define IMX_SC_R_DC_0_FRAC0 30
#define IMX_SC_R_V2X_MU_2 31
#define IMX_SC_R_DC_0 32
#define IMX_SC_R_GPU_2_PID0 33
#define IMX_SC_R_DC_0_PLL_0 34
@ -49,7 +53,10 @@
#define IMX_SC_R_DC_1_BLIT1 37
#define IMX_SC_R_DC_1_BLIT2 38
#define IMX_SC_R_DC_1_BLIT_OUT 39
#define IMX_SC_R_V2X_MU_3 40
#define IMX_SC_R_V2X_MU_4 41
#define IMX_SC_R_DC_1_WARP 42
#define IMX_SC_R_SECVIO 44
#define IMX_SC_R_DC_1_VIDEO0 45
#define IMX_SC_R_DC_1_VIDEO1 46
#define IMX_SC_R_DC_1_FRAC0 47

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
/*
* Copyright 2022 NXP
*/
#ifndef __DT_BINDINGS_IMX93_POWER_H__
#define __DT_BINDINGS_IMX93_POWER_H__
#define IMX93_MEDIABLK_PD_MIPI_DSI 0
#define IMX93_MEDIABLK_PD_MIPI_CSI 1
#define IMX93_MEDIABLK_PD_PXP 2
#define IMX93_MEDIABLK_PD_LCDIF 3
#define IMX93_MEDIABLK_PD_ISI 4
#endif

View File

@ -49,5 +49,11 @@
#define IMX8MP_HDMIBLK_PD_TRNG 4
#define IMX8MP_HDMIBLK_PD_HDMI_TX 5
#define IMX8MP_HDMIBLK_PD_HDMI_TX_PHY 6
#define IMX8MP_HDMIBLK_PD_HDCP 7
#define IMX8MP_HDMIBLK_PD_HRV 8
#define IMX8MP_VPUBLK_PD_G1 0
#define IMX8MP_VPUBLK_PD_G2 1
#define IMX8MP_VPUBLK_PD_VC8000E 2
#endif