Pull ARM driver updates from Arnd Bergmann: "These are the usual updates for SoC specific device drivers and related subsystems that don't have their own top-level maintainers: - ARM SCMI/SCPI updates to allow pluggable transport layers - TEE subsystem cleanups - A new driver for the Amlogic secure power domain controller - Various driver updates for the NXP Layerscape DPAA2, NXP i.MX SCU and TI OMAP2+ sysc drivers. - Qualcomm SoC driver updates, including a new library module for "protection domain" notifications - Lots of smaller bugfixes and cleanups in other drivers" * tag 'arm-drivers-5.7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (70 commits) soc: fsl: qe: fix sparse warnings for ucc_slow.c soc: fsl: qe: ucc_slow: remove 0 assignment for kzalloc'ed structure soc: fsl: qe: fix sparse warnings for ucc_fast.c soc: fsl: qe: fix sparse warnings for qe_ic.c soc: fsl: qe: fix sparse warnings for ucc.c soc: fsl: qe: fix sparse warning for qe_common.c soc: fsl: qe: fix sparse warnings for qe.c soc: qcom: Fix QCOM_APR dependencies soc: qcom: pdr: Avoid uninitialized use of found in pdr_indication_cb soc: imx: drop COMPILE_TEST for IMX_SCU_SOC firmware: imx: add COMPILE_TEST for IMX_SCU driver soc: imx: gpc: fix power up sequencing soc: imx: increase build coverage for imx8m soc driver soc: qcom: apr: Add avs/audio tracking functionality dt-bindings: soc: qcom: apr: Add protection domain bindings soc: qcom: Introduce Protection Domain Restart helpers devicetree: bindings: firmware: add ipq806x to qcom_scm memory: tegra: Correct debugfs clk rate-range on Tegra124 memory: tegra: Correct debugfs clk rate-range on Tegra30 memory: tegra: Correct debugfs clk rate-range on Tegra20 ...
Unified · Split
| @@ -38,6 +38,7 @@ Required standard properties: · 37 unmodified lines | |||
| 38 | "ti,sysc-dra7-mcasp" | 38 | "ti,sysc-dra7-mcasp" |
| 39 | "ti,sysc-usb-host-fs" | 39 | "ti,sysc-usb-host-fs" |
| 40 | "ti,sysc-dra7-mcan" | 40 | "ti,sysc-dra7-mcan" |
| 41 | "ti,sysc-pruss" | ||
| 41 | 42 | ||
| 42 | - reg shall have register areas implemented for the interconnect | 43 | - reg shall have register areas implemented for the interconnect |
| 43 | target module in question such as revision, sysc and syss | 44 | target module in question such as revision, sysc and syss |
| @@ -10,6 +10,7 @@ Required properties: · 9 unmodified lines | |||
| 10 | * "qcom,scm-apq8064" | 10 | * "qcom,scm-apq8064" |
| 11 | * "qcom,scm-apq8084" | 11 | * "qcom,scm-apq8084" |
| 12 | * "qcom,scm-ipq4019" | 12 | * "qcom,scm-ipq4019" |
| 13 | * "qcom,scm-ipq806x" | ||
| 13 | * "qcom,scm-msm8660" | 14 | * "qcom,scm-msm8660" |
| 14 | * "qcom,scm-msm8916" | 15 | * "qcom,scm-msm8916" |
| 15 | * "qcom,scm-msm8960" | 16 | * "qcom,scm-msm8960" |
| @@ -0,0 +1,40 @@ | |||
| 1 | # SPDX-License-Identifier: (GPL-2.0+ OR MIT) | ||
| 2 | # Copyright (c) 2019 Amlogic, Inc | ||
| 3 | # Author: Jianxin Pan <jianxin.pan@amlogic.com> | ||
| 4 | %YAML 1.2 | ||
| 5 | --- | ||
| 6 | $id: "http://devicetree.org/schemas/power/amlogic,meson-sec-pwrc.yaml#" | ||
| 7 | $schema: "http://devicetree.org/meta-schemas/core.yaml#" | ||
| 8 | |||
| 9 | title: Amlogic Meson Secure Power Domains | ||
| 10 | |||
| 11 | maintainers: | ||
| 12 | - Jianxin Pan <jianxin.pan@amlogic.com> | ||
| 13 | |||
| 14 | description: |+ | ||
| 15 | Secure Power Domains used in Meson A1/C1 SoCs, and should be the child node | ||
| 16 | of secure-monitor. | ||
| 17 | |||
| 18 | properties: | ||
| 19 | compatible: | ||
| 20 | enum: | ||
| 21 | - amlogic,meson-a1-pwrc | ||
| 22 | |||
| 23 | "#power-domain-cells": | ||
| 24 | const: 1 | ||
| 25 | |||
| 26 | required: | ||
| 27 | - compatible | ||
| 28 | - "#power-domain-cells" | ||
| 29 | |||
| 30 | examples: | ||
| 31 | - | | ||
| 32 | secure-monitor { | ||
| 33 | compatible = "amlogic,meson-gxbb-sm"; | ||
| 34 | |||
| 35 | pwrc: power-controller { | ||
| 36 | compatible = "amlogic,meson-a1-pwrc"; | ||
| 37 | #power-domain-cells = <1>; | ||
| 38 | }; | ||
| 39 | }; | ||
| 40 | |||
| @@ -45,6 +45,18 @@ by the individual bindings for the specific service · 44 unmodified lines | |||
| 45 | 12 - Ultrasound stream manager. | 45 | 12 - Ultrasound stream manager. |
| 46 | 13 - Listen stream manager. | 46 | 13 - Listen stream manager. |
| 47 | 47 | ||
| 48 | - qcom,protection-domain | ||
| 49 | Usage: optional | ||
| 50 | Value type: <stringlist> | ||
| 51 | Definition: Must list the protection domain service name and path | ||
| 52 | that the particular apr service has a dependency on. | ||
| 53 | Possible values are : | ||
| 54 | "avs/audio", "msm/adsp/audio_pd". | ||
| 55 | "kernel/elf_loader", "msm/modem/wlan_pd". | ||
| 56 | "tms/servreg", "msm/adsp/audio_pd". | ||
| 57 | "tms/servreg", "msm/modem/wlan_pd". | ||
| 58 | "tms/servreg", "msm/slpi/sensor_pd". | ||
| 59 | |||
| 48 | = EXAMPLE | 60 | = EXAMPLE |
| 49 | The following example represents a QDSP based sound card on a MSM8996 device | 61 | The following example represents a QDSP based sound card on a MSM8996 device |
| 50 | which uses apr as communication between Apps and QDSP. | 62 | which uses apr as communication between Apps and QDSP. |
| @@ -82,3 +94,41 @@ which uses apr as communication between Apps and QDSP. · 31 unmodified lines | |||
| 82 | ... | 94 | ... |
| 83 | }; | 95 | }; |
| 84 | }; | 96 | }; |
| 97 | |||
| 98 | = EXAMPLE 2 | ||
| 99 | The following example represents a QDSP based sound card with protection domain | ||
| 100 | dependencies specified. Here some of the apr services are dependent on services | ||
| 101 | running on protection domain hosted on ADSP/SLPI remote processors while others | ||
| 102 | have no such dependency. | ||
| 103 | |||
| 104 | apr { | ||
| 105 | compatible = "qcom,apr-v2"; | ||
| 106 | qcom,glink-channels = "apr_audio_svc"; | ||
| 107 | qcom,apr-domain = <APR_DOMAIN_ADSP>; | ||
| 108 | |||
| 109 | q6core { | ||
| 110 | compatible = "qcom,q6core"; | ||
| 111 | reg = <APR_SVC_ADSP_CORE>; | ||
| 112 | }; | ||
| 113 | |||
| 114 | q6afe: q6afe { | ||
| 115 | compatible = "qcom,q6afe"; | ||
| 116 | reg = <APR_SVC_AFE>; | ||
| 117 | qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; | ||
| 118 | ... | ||
| 119 | }; | ||
| 120 | |||
| 121 | q6asm: q6asm { | ||
| 122 | compatible = "qcom,q6asm"; | ||
| 123 | reg = <APR_SVC_ASM>; | ||
| 124 | qcom,protection-domain = "tms/servreg", "msm/slpi/sensor_pd"; | ||
| 125 | ... | ||
| 126 | }; | ||
| 127 | |||
| 128 | q6adm: q6adm { | ||
| 129 | compatible = "qcom,q6adm"; | ||
| 130 | reg = <APR_SVC_ADM>; | ||
| 131 | qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd"; | ||
| 132 | ... | ||
| 133 | }; | ||
| 134 | }; | ||
| @@ -397,10 +397,16 @@ static int ti_sysc_shutdown_module(struct device *dev, · 396 unmodified lines | |||
| 397 | return omap_hwmod_shutdown(cookie->data); | 397 | return omap_hwmod_shutdown(cookie->data); |
| 398 | } | 398 | } |
| 399 | 399 | ||
| 400 | static bool ti_sysc_soc_type_gp(void) | ||
| 401 | { | ||
| 402 | return omap_type() == OMAP2_DEVICE_TYPE_GP; | ||
| 403 | } | ||
| 404 | |||
| 400 | static struct of_dev_auxdata omap_auxdata_lookup[]; | 405 | static struct of_dev_auxdata omap_auxdata_lookup[]; |
| 401 | 406 | ||
| 402 | static struct ti_sysc_platform_data ti_sysc_pdata = { | 407 | static struct ti_sysc_platform_data ti_sysc_pdata = { |
| 403 | .auxdata = omap_auxdata_lookup, | 408 | .auxdata = omap_auxdata_lookup, |
| 409 | .soc_type_gp = ti_sysc_soc_type_gp, | ||
| 404 | .init_clockdomain = ti_sysc_clkdm_init, | 410 | .init_clockdomain = ti_sysc_clkdm_init, |
| 405 | .clkdm_deny_idle = ti_sysc_clkdm_deny_idle, | 411 | .clkdm_deny_idle = ti_sysc_clkdm_deny_idle, |
| 406 | .clkdm_allow_idle = ti_sysc_clkdm_allow_idle, | 412 | .clkdm_allow_idle = ti_sysc_clkdm_allow_idle, |
| @@ -357,6 +357,26 @@ static int hisi_lpc_acpi_xlat_io_res(struct acpi_device *adev, · 356 unmodified lines | |||
| 357 | return 0; | 357 | return 0; |
| 358 | } | 358 | } |
| 359 | 359 | ||
| 360 | /* | ||
| 361 | * Released firmware describes the IO port max address as 0x3fff, which is | ||
| 362 | * the max host bus address. Fixup to a proper range. This will probably | ||
| 363 | * never be fixed in firmware. | ||
| 364 | */ | ||
| 365 | static void hisi_lpc_acpi_fixup_child_resource(struct device *hostdev, | ||
| 366 | struct resource *r) | ||
| 367 | { | ||
| 368 | if (r->end != 0x3fff) | ||
| 369 | return; | ||
| 370 | |||
| 371 | if (r->start == 0xe4) | ||
| 372 | r->end = 0xe4 + 0x04 - 1; | ||
| 373 | else if (r->start == 0x2f8) | ||
| 374 | r->end = 0x2f8 + 0x08 - 1; | ||
| 375 | else | ||
| 376 | dev_warn(hostdev, "unrecognised resource %pR to fixup, ignoring\n", | ||
| 377 | r); | ||
| 378 | } | ||
| 379 | |||
| 360 | /* | 380 | /* |
| 361 | * hisi_lpc_acpi_set_io_res - set the resources for a child | 381 | * hisi_lpc_acpi_set_io_res - set the resources for a child |
| 362 | * @child: the device node to be updated the I/O resource | 382 | * @child: the device node to be updated the I/O resource |
| @@ -418,8 +438,11 @@ static int hisi_lpc_acpi_set_io_res(struct device *child, · 55 unmodified lines | |||
| 418 | return -ENOMEM; | 438 | return -ENOMEM; |
| 419 | } | 439 | } |
| 420 | count = 0; | 440 | count = 0; |
| 421 | list_for_each_entry(rentry, &resource_list, node) | 441 | list_for_each_entry(rentry, &resource_list, node) { |
| 422 | resources[count++] = *rentry->res; | 442 | resources[count] = *rentry->res; |
| 443 | hisi_lpc_acpi_fixup_child_resource(hostdev, &resources[count]); | ||
| 444 | count++; | ||
| 445 | } | ||
| 423 | 446 | ||
| 424 | acpi_dev_free_resource_list(&resource_list); | 447 | acpi_dev_free_resource_list(&resource_list); |
| 425 | 448 | ||
| @@ -7,6 +7,7 @@ · 6 unmodified lines | |||
| 7 | #include <linux/clk.h> | 7 | #include <linux/clk.h> |
| 8 | #include <linux/clkdev.h> | 8 | #include <linux/clkdev.h> |
| 9 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 10 | #include <linux/list.h> | ||
| 10 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 11 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
| 12 | #include <linux/pm_domain.h> | 13 | #include <linux/pm_domain.h> |
| @@ -15,15 +16,47 @@ · 2 unmodified lines | |||
| 15 | #include <linux/of_address.h> | 16 | #include <linux/of_address.h> |
| 16 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
| 17 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/sys_soc.h> | ||
| 18 | #include <linux/iopoll.h> | 20 | #include <linux/iopoll.h> |
| 19 | 21 | ||
| 20 | #include <linux/platform_data/ti-sysc.h> | 22 | #include <linux/platform_data/ti-sysc.h> |
| 21 | 23 | ||
| 22 | #include <dt-bindings/bus/ti-sysc.h> | 24 | #include <dt-bindings/bus/ti-sysc.h> |
| 23 | 25 | ||
| 26 | #define DIS_ISP BIT(2) | ||
| 27 | #define DIS_IVA BIT(1) | ||
| 28 | #define DIS_SGX BIT(0) | ||
| 29 | |||
| 30 | #define SOC_FLAG(match, flag) { .machine = match, .data = (void *)(flag), } | ||
| 31 | |||
| 24 | #define MAX_MODULE_SOFTRESET_WAIT 10000 | 32 | #define MAX_MODULE_SOFTRESET_WAIT 10000 |
| 25 | 33 | ||
| 26 | static const char * const reg_names[] = { "rev", "sysc", "syss", }; | 34 | enum sysc_soc { |
| 35 | SOC_UNKNOWN, | ||
| 36 | SOC_2420, | ||
| 37 | SOC_2430, | ||
| 38 | SOC_3430, | ||
| 39 | SOC_3630, | ||
| 40 | SOC_4430, | ||
| 41 | SOC_4460, | ||
| 42 | SOC_4470, | ||
| 43 | SOC_5430, | ||
| 44 | SOC_AM3, | ||
| 45 | SOC_AM4, | ||
| 46 | SOC_DRA7, | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct sysc_address { | ||
| 50 | unsigned long base; | ||
| 51 | struct list_head node; | ||
| 52 | }; | ||
| 53 | |||
| 54 | struct sysc_soc_info { | ||
| 55 | unsigned long general_purpose:1; | ||
| 56 | enum sysc_soc soc; | ||
| 57 | struct mutex list_lock; /* disabled modules list lock */ | ||
| 58 | struct list_head disabled_modules; | ||
| 59 | }; | ||
| 27 | 60 | ||
| 28 | enum sysc_clocks { | 61 | enum sysc_clocks { |
| 29 | SYSC_FCK, | 62 | SYSC_FCK, |
| @@ -39,6 +72,8 @@ enum sysc_clocks { · 9 unmodified lines | |||
| 39 | SYSC_MAX_CLOCKS, | 72 | SYSC_MAX_CLOCKS, |
| 40 | }; | 73 | }; |
| 41 | 74 | ||
| 75 | static struct sysc_soc_info *sysc_soc; | ||
| 76 | static const char * const reg_names[] = { "rev", "sysc", "syss", }; | ||
| 42 | static const char * const clock_names[SYSC_MAX_CLOCKS] = { | 77 | static const char * const clock_names[SYSC_MAX_CLOCKS] = { |
| 43 | "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4", | 78 | "fck", "ick", "opt0", "opt1", "opt2", "opt3", "opt4", |
| 44 | "opt5", "opt6", "opt7", | 79 | "opt5", "opt6", "opt7", |
| @@ -70,11 +105,13 @@ static const char * const clock_names[SYSC_MAX_CLOCKS] = { · 25 unmodified lines | |||
| 70 | * @child_needs_resume: runtime resume needed for child on resume from suspend | 105 | * @child_needs_resume: runtime resume needed for child on resume from suspend |
| 71 | * @disable_on_idle: status flag used for disabling modules with resets | 106 | * @disable_on_idle: status flag used for disabling modules with resets |
| 72 | * @idle_work: work structure used to perform delayed idle on a module | 107 | * @idle_work: work structure used to perform delayed idle on a module |
| 73 | * @clk_enable_quirk: module specific clock enable quirk | 108 | * @pre_reset_quirk: module specific pre-reset quirk |
| 74 | * @clk_disable_quirk: module specific clock disable quirk | 109 | * @post_reset_quirk: module specific post-reset quirk |
| 75 | * @reset_done_quirk: module specific reset done quirk | 110 | * @reset_done_quirk: module specific reset done quirk |
| 76 | * @module_enable_quirk: module specific enable quirk | 111 | * @module_enable_quirk: module specific enable quirk |
| 77 | * @module_disable_quirk: module specific disable quirk | 112 | * @module_disable_quirk: module specific disable quirk |
| 113 | * @module_unlock_quirk: module specific sysconfig unlock quirk | ||
| 114 | * @module_lock_quirk: module specific sysconfig lock quirk | ||
| 78 | */ | 115 | */ |
| 79 | struct sysc { | 116 | struct sysc { |
| 80 | struct device *dev; | 117 | struct device *dev; |
| @@ -97,11 +134,13 @@ struct sysc { · 16 unmodified lines | |||
| 97 | unsigned int needs_resume:1; | 134 | unsigned int needs_resume:1; |
| 98 | unsigned int child_needs_resume:1; | 135 | unsigned int child_needs_resume:1; |
| 99 | struct delayed_work idle_work; | 136 | struct delayed_work idle_work; |
| 100 | void (*clk_enable_quirk)(struct sysc *sysc); | 137 | void (*pre_reset_quirk)(struct sysc *sysc); |
| 101 | void (*clk_disable_quirk)(struct sysc *sysc); | 138 | void (*post_reset_quirk)(struct sysc *sysc); |
| 102 | void (*reset_done_quirk)(struct sysc *sysc); | 139 | void (*reset_done_quirk)(struct sysc *sysc); |
| 103 | void (*module_enable_quirk)(struct sysc *sysc); | 140 | void (*module_enable_quirk)(struct sysc *sysc); |
| 104 | void (*module_disable_quirk)(struct sysc *sysc); | 141 | void (*module_disable_quirk)(struct sysc *sysc); |
| 142 | void (*module_unlock_quirk)(struct sysc *sysc); | ||
| 143 | void (*module_lock_quirk)(struct sysc *sysc); | ||
| 105 | }; | 144 | }; |
| 106 | 145 | ||
| 107 | static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, | 146 | static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, |
| @@ -624,7 +663,7 @@ static void sysc_check_one_child(struct sysc *ddata, · 516 unmodified lines | |||
| 624 | const char *name; | 663 | const char *name; |
| 625 | 664 | ||
| 626 | name = of_get_property(np, "ti,hwmods", NULL); | 665 | name = of_get_property(np, "ti,hwmods", NULL); |
| 627 | if (name) | 666 | if (name && !of_device_is_compatible(np, "ti,sysc")) |
| 628 | dev_warn(ddata->dev, "really a child ti,hwmods property?"); | 667 | dev_warn(ddata->dev, "really a child ti,hwmods property?"); |
| 629 | 668 | ||
| 630 | sysc_check_quirk_stdout(ddata, np); | 669 | sysc_check_quirk_stdout(ddata, np); |
| @@ -861,6 +900,22 @@ static void sysc_show_registers(struct sysc *ddata) · 230 unmodified lines | |||
| 861 | buf); | 900 | buf); |
| 862 | } | 901 | } |
| 863 | 902 | ||
| 903 | /** | ||
| 904 | * sysc_write_sysconfig - handle sysconfig quirks for register write | ||
| 905 | * @ddata: device driver data | ||
| 906 | * @value: register value | ||
| 907 | */ | ||
| 908 | static void sysc_write_sysconfig(struct sysc *ddata, u32 value) | ||
| 909 | { | ||
| 910 | if (ddata->module_unlock_quirk) | ||
| 911 | ddata->module_unlock_quirk(ddata); | ||
| 912 | |||
| 913 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], value); | ||
| 914 | |||
| 915 | if (ddata->module_lock_quirk) | ||
| 916 | ddata->module_lock_quirk(ddata); | ||
| 917 | } | ||
| 918 | |||
| 864 | #define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1) | 919 | #define SYSC_IDLE_MASK (SYSC_NR_IDLEMODES - 1) |
| 865 | #define SYSC_CLOCACT_ICK 2 | 920 | #define SYSC_CLOCACT_ICK 2 |
| 866 | 921 | ||
| @@ -907,7 +962,7 @@ static int sysc_enable_module(struct device *dev) · 40 unmodified lines | |||
| 907 | 962 | ||
| 908 | reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); | 963 | reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); |
| 909 | reg |= best_mode << regbits->sidle_shift; | 964 | reg |= best_mode << regbits->sidle_shift; |
| 910 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | 965 | sysc_write_sysconfig(ddata, reg); |
| 911 | 966 | ||
| 912 | set_midle: | 967 | set_midle: |
| 913 | /* Set MIDLE mode */ | 968 | /* Set MIDLE mode */ |
| @@ -926,14 +981,14 @@ set_midle: · 12 unmodified lines | |||
| 926 | 981 | ||
| 927 | reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); | 982 | reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); |
| 928 | reg |= best_mode << regbits->midle_shift; | 983 | reg |= best_mode << regbits->midle_shift; |
| 929 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | 984 | sysc_write_sysconfig(ddata, reg); |
| 930 | 985 | ||
| 931 | set_autoidle: | 986 | set_autoidle: |
| 932 | /* Autoidle bit must enabled separately if available */ | 987 | /* Autoidle bit must enabled separately if available */ |
| 933 | if (regbits->autoidle_shift >= 0 && | 988 | if (regbits->autoidle_shift >= 0 && |
| 934 | ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) { | 989 | ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) { |
| 935 | reg |= 1 << regbits->autoidle_shift; | 990 | reg |= 1 << regbits->autoidle_shift; |
| 936 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | 991 | sysc_write_sysconfig(ddata, reg); |
| 937 | } | 992 | } |
| 938 | 993 | ||
| 939 | if (ddata->module_enable_quirk) | 994 | if (ddata->module_enable_quirk) |
| @@ -991,7 +1046,7 @@ static int sysc_disable_module(struct device *dev) · 51 unmodified lines | |||
| 991 | 1046 | ||
| 992 | reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); | 1047 | reg &= ~(SYSC_IDLE_MASK << regbits->midle_shift); |
| 993 | reg |= best_mode << regbits->midle_shift; | 1048 | reg |= best_mode << regbits->midle_shift; |
| 994 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | 1049 | sysc_write_sysconfig(ddata, reg); |
| 995 | 1050 | ||
| 996 | set_sidle: | 1051 | set_sidle: |
| 997 | /* Set SIDLE mode */ | 1052 | /* Set SIDLE mode */ |
| @@ -1014,7 +1069,7 @@ set_sidle: · 16 unmodified lines | |||
| 1014 | if (regbits->autoidle_shift >= 0 && | 1069 | if (regbits->autoidle_shift >= 0 && |
| 1015 | ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) | 1070 | ddata->cfg.sysc_val & BIT(regbits->autoidle_shift)) |
| 1016 | reg |= 1 << regbits->autoidle_shift; | 1071 | reg |= 1 << regbits->autoidle_shift; |
| 1017 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | 1072 | sysc_write_sysconfig(ddata, reg); |
| 1018 | 1073 | ||
| 1019 | return 0; | 1074 | return 0; |
| 1020 | } | 1075 | } |
| @@ -1216,16 +1271,16 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 195 unmodified lines | |||
| 1216 | SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), | 1271 | SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), |
| 1217 | SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, | 1272 | SYSC_QUIRK("sham", 0, 0x100, 0x110, 0x114, 0x40000c03, 0xffffffff, |
| 1218 | SYSC_QUIRK_LEGACY_IDLE), | 1273 | SYSC_QUIRK_LEGACY_IDLE), |
| 1219 | SYSC_QUIRK("smartreflex", 0, -1, 0x24, -1, 0x00000000, 0xffffffff, | 1274 | SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x24, -ENODEV, 0x00000000, 0xffffffff, |
| 1220 | SYSC_QUIRK_LEGACY_IDLE), | 1275 | SYSC_QUIRK_LEGACY_IDLE), |
| 1221 | SYSC_QUIRK("smartreflex", 0, -1, 0x38, -1, 0x00000000, 0xffffffff, | 1276 | SYSC_QUIRK("smartreflex", 0, -ENODEV, 0x38, -ENODEV, 0x00000000, 0xffffffff, |
| 1222 | SYSC_QUIRK_LEGACY_IDLE), | 1277 | SYSC_QUIRK_LEGACY_IDLE), |
| 1223 | SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, | 1278 | SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, |
| 1224 | 0), | 1279 | 0), |
| 1225 | /* Some timers on omap4 and later */ | 1280 | /* Some timers on omap4 and later */ |
| 1226 | SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff, | 1281 | SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x50002100, 0xffffffff, |
| 1227 | 0), | 1282 | 0), |
| 1228 | SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff, | 1283 | SYSC_QUIRK("timer", 0, 0, 0x10, -ENODEV, 0x4fff1301, 0xffff00ff, |
| 1229 | 0), | 1284 | 0), |
| 1230 | SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, | 1285 | SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, |
| 1231 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), | 1286 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), |
| @@ -1238,19 +1293,27 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 6 unmodified lines | |||
| 1238 | SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), | 1293 | SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), |
| 1239 | 1294 | ||
| 1240 | /* Quirks that need to be set based on the module address */ | 1295 | /* Quirks that need to be set based on the module address */ |
| 1241 | SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -1, 0x50000800, 0xffffffff, | 1296 | SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff, |
| 1242 | SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT | | 1297 | SYSC_QUIRK_EXT_OPT_CLOCK | SYSC_QUIRK_NO_RESET_ON_INIT | |
| 1243 | SYSC_QUIRK_SWSUP_SIDLE), | 1298 | SYSC_QUIRK_SWSUP_SIDLE), |
| 1244 | 1299 | ||
| 1245 | /* Quirks that need to be set based on detected module */ | 1300 | /* Quirks that need to be set based on detected module */ |
| 1246 | SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, | 1301 | SYSC_QUIRK("aess", 0, 0, 0x10, -ENODEV, 0x40000000, 0xffffffff, |
| 1247 | SYSC_MODULE_QUIRK_AESS), | 1302 | SYSC_MODULE_QUIRK_AESS), |
| 1248 | SYSC_QUIRK("dcan", 0x48480000, 0x20, -1, -1, 0xa3170504, 0xffffffff, | 1303 | SYSC_QUIRK("dcan", 0x48480000, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, |
| 1249 | SYSC_QUIRK_CLKDM_NOAUTO), | 1304 | SYSC_QUIRK_CLKDM_NOAUTO), |
| 1250 | SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -1, 0x500a0200, 0xffffffff, | 1305 | SYSC_QUIRK("dss", 0x4832a000, 0, 0x10, 0x14, 0x00000020, 0xffffffff, |
| 1306 | SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | ||
| 1307 | SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000040, 0xffffffff, | ||
| 1308 | SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | ||
| 1309 | SYSC_QUIRK("dss", 0x58000000, 0, -ENODEV, 0x14, 0x00000061, 0xffffffff, | ||
| 1310 | SYSC_QUIRK_OPT_CLKS_IN_RESET | SYSC_MODULE_QUIRK_DSS_RESET), | ||
| 1311 | SYSC_QUIRK("dwc3", 0x48880000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, | ||
| 1251 | SYSC_QUIRK_CLKDM_NOAUTO), | 1312 | SYSC_QUIRK_CLKDM_NOAUTO), |
| 1252 | SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -1, 0x500a0200, 0xffffffff, | 1313 | SYSC_QUIRK("dwc3", 0x488c0000, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, |
| 1253 | SYSC_QUIRK_CLKDM_NOAUTO), | 1314 | SYSC_QUIRK_CLKDM_NOAUTO), |
| 1315 | SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50030200, 0xffffffff, | ||
| 1316 | SYSC_QUIRK_OPT_CLKS_NEEDED), | ||
| 1254 | SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, | 1317 | SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, |
| 1255 | SYSC_MODULE_QUIRK_HDQ1W), | 1318 | SYSC_MODULE_QUIRK_HDQ1W), |
| 1256 | SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, | 1319 | SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, |
| @@ -1263,72 +1326,92 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { · 6 unmodified lines | |||
| 1263 | SYSC_MODULE_QUIRK_I2C), | 1326 | SYSC_MODULE_QUIRK_I2C), |
| 1264 | SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, | 1327 | SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, |
| 1265 | SYSC_MODULE_QUIRK_I2C), | 1328 | SYSC_MODULE_QUIRK_I2C), |
| 1266 | SYSC_QUIRK("gpu", 0x50000000, 0x14, -1, -1, 0x00010201, 0xffffffff, 0), | 1329 | SYSC_QUIRK("gpu", 0x50000000, 0x14, -ENODEV, -ENODEV, 0x00010201, 0xffffffff, 0), |
| 1267 | SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, | 1330 | SYSC_QUIRK("gpu", 0x50000000, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, |
| 1268 | SYSC_MODULE_QUIRK_SGX), | 1331 | SYSC_MODULE_QUIRK_SGX), |
| 1269 | SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, | 1332 | SYSC_QUIRK("lcdc", 0, 0, 0x54, -ENODEV, 0x4f201000, 0xffffffff, |
| 1333 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), | ||
| 1334 | SYSC_QUIRK("rtc", 0, 0x74, 0x78, -ENODEV, 0x4eb01908, 0xffff00f0, | ||
| 1335 | SYSC_MODULE_QUIRK_RTC_UNLOCK), | ||
| 1336 | SYSC_QUIRK("tptc", 0, 0, 0x10, -ENODEV, 0x40006c00, 0xffffefff, | ||
| 1337 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), | ||
| 1338 | SYSC_QUIRK("tptc", 0, 0, -ENODEV, -ENODEV, 0x40007c00, 0xffffffff, | ||
| 1270 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), | 1339 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), |
| 1271 | SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, | 1340 | SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, |
| 1272 | 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), | 1341 | 0xffffffff, SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), |
| 1273 | SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -1, 0x4ea2080d, 0xffffffff, | 1342 | SYSC_QUIRK("usb_otg_hs", 0, 0, 0x10, -ENODEV, 0x4ea2080d, 0xffffffff, |
| 1274 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), | 1343 | SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_MSTANDBY), |
| 1275 | SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, | 1344 | SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, |
| 1276 | SYSC_MODULE_QUIRK_WDT), | 1345 | SYSC_MODULE_QUIRK_WDT), |
| 1346 | /* PRUSS on am3, am4 and am5 */ | ||
| 1347 | SYSC_QUIRK("pruss", 0, 0x26000, 0x26004, -ENODEV, 0x47000000, 0xff000000, | ||
| 1348 | SYSC_MODULE_QUIRK_PRUSS), | ||
| 1277 | /* Watchdog on am3 and am4 */ | 1349 | /* Watchdog on am3 and am4 */ |
| 1278 | SYSC_QUIRK("wdt", 0x44e35000, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, | 1350 | SYSC_QUIRK("wdt", 0x44e35000, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, |
| 1279 | SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE), | 1351 | SYSC_MODULE_QUIRK_WDT | SYSC_QUIRK_SWSUP_SIDLE), |
| 1280 | 1352 | ||
| 1281 | #ifdef DEBUG | 1353 | #ifdef DEBUG |
| 1282 | SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0), | 1354 | SYSC_QUIRK("adc", 0, 0, 0x10, -ENODEV, 0x47300001, 0xffffffff, 0), |
| 1283 | SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0), | 1355 | SYSC_QUIRK("atl", 0, 0, -ENODEV, -ENODEV, 0x0a070100, 0xffffffff, 0), |
| 1284 | SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0), | 1356 | SYSC_QUIRK("cm", 0, 0, -ENODEV, -ENODEV, 0x40000301, 0xffffffff, 0), |
| 1285 | SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0), | 1357 | SYSC_QUIRK("control", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), |
| 1286 | SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902, | 1358 | SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902, |
| 1287 | 0xffff00f0, 0), | 1359 | 0xffff00f0, 0), |
| 1288 | SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0xa3170504, 0xffffffff, 0), | 1360 | SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0xa3170504, 0xffffffff, 0), |
| 1289 | SYSC_QUIRK("dcan", 0, 0x20, -1, -1, 0x4edb1902, 0xffffffff, 0), | 1361 | SYSC_QUIRK("dcan", 0, 0x20, -ENODEV, -ENODEV, 0x4edb1902, 0xffffffff, 0), |
| 1290 | SYSC_QUIRK("dmic", 0, 0, 0x10, -1, 0x50010000, 0xffffffff, 0), | 1362 | SYSC_QUIRK("dispc", 0x4832a400, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), |
| 1291 | SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0), | 1363 | SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), |
| 1364 | SYSC_QUIRK("dispc", 0x58001000, 0, 0x10, 0x14, 0x00000051, 0xffffffff, 0), | ||
| 1365 | SYSC_QUIRK("dmic", 0, 0, 0x10, -ENODEV, 0x50010000, 0xffffffff, 0), | ||
| 1366 | SYSC_QUIRK("dsi", 0x58004000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), | ||
| 1367 | SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000030, 0xffffffff, 0), | ||
| 1368 | SYSC_QUIRK("dsi", 0x58005000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), | ||
| 1369 | SYSC_QUIRK("dsi", 0x58009000, 0, 0x10, 0x14, 0x00000040, 0xffffffff, 0), | ||
| 1370 | SYSC_QUIRK("dwc3", 0, 0, 0x10, -ENODEV, 0x500a0200, 0xffffffff, 0), | ||
| 1292 | SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), | 1371 | SYSC_QUIRK("d2d", 0x4a0b6000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), |
| 1293 | SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), | 1372 | SYSC_QUIRK("d2d", 0x4a0cd000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), |
| 1294 | SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0), | 1373 | SYSC_QUIRK("epwmss", 0, 0, 0x4, -ENODEV, 0x47400001, 0xffffffff, 0), |
| 1295 | SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), | 1374 | SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -ENODEV, 0, 0, 0), |
| 1296 | SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -1, 0x40000000 , 0xffffffff, 0), | 1375 | SYSC_QUIRK("gpu", 0, 0xfe00, 0xfe10, -ENODEV, 0x40000000 , 0xffffffff, 0), |
| 1376 | SYSC_QUIRK("hdmi", 0, 0, 0x10, -ENODEV, 0x50031d00, 0xffffffff, 0), | ||
| 1297 | SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), | 1377 | SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), |
| 1298 | SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), | 1378 | SYSC_QUIRK("iss", 0, 0, 0x10, -ENODEV, 0x40000101, 0xffffffff, 0), |
| 1299 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0), | 1379 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44306302, 0xffffffff, 0), |
| 1300 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0), | 1380 | SYSC_QUIRK("mcasp", 0, 0, 0x4, -ENODEV, 0x44307b02, 0xffffffff, 0), |
| 1301 | SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0), | 1381 | SYSC_QUIRK("mcbsp", 0, -ENODEV, 0x8c, -ENODEV, 0, 0, 0), |
| 1302 | SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0), | 1382 | SYSC_QUIRK("mcspi", 0, 0, 0x10, -ENODEV, 0x40300a0b, 0xffff00ff, 0), |
| 1303 | SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0), | 1383 | SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0), |
| 1304 | SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0), | 1384 | SYSC_QUIRK("mailbox", 0, 0, 0x10, -ENODEV, 0x00000400, 0xffffffff, 0), |
| 1305 | SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0), | 1385 | SYSC_QUIRK("m3", 0, 0, -ENODEV, -ENODEV, 0x5f580105, 0x0fff0f00, 0), |
| 1306 | SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), | 1386 | SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), |
| 1307 | SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0), | 1387 | SYSC_QUIRK("ocp2scp", 0, 0, -ENODEV, -ENODEV, 0x50060007, 0xffffffff, 0), |
| 1308 | SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0), | 1388 | SYSC_QUIRK("padconf", 0, 0, 0x10, -ENODEV, 0x4fff0800, 0xffffffff, 0), |
| 1309 | SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0), | 1389 | SYSC_QUIRK("padconf", 0, 0, -ENODEV, -ENODEV, 0x40001100, 0xffffffff, 0), |
| 1310 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0), | 1390 | SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000100, 0xffffffff, 0), |
| 1311 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0), | 1391 | SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x00004102, 0xffffffff, 0), |
| 1312 | SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0), | 1392 | SYSC_QUIRK("prcm", 0, 0, -ENODEV, -ENODEV, 0x40000400, 0xffffffff, 0), |
| 1313 | SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0), | 1393 | SYSC_QUIRK("rfbi", 0x4832a800, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), |
| 1314 | SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0), | 1394 | SYSC_QUIRK("rfbi", 0x58002000, 0, 0x10, 0x14, 0x00000010, 0xffffffff, 0), |
| 1315 | SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0), | 1395 | SYSC_QUIRK("scm", 0, 0, 0x10, -ENODEV, 0x40000900, 0xffffffff, 0), |
| 1316 | SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0), | 1396 | SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4e8b0100, 0xffffffff, 0), |
| 1317 | SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0), | 1397 | SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x4f000100, 0xffffffff, 0), |
| 1318 | SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0), | 1398 | SYSC_QUIRK("scm", 0, 0, -ENODEV, -ENODEV, 0x40000900, 0xffffffff, 0), |
| 1399 | SYSC_QUIRK("scrm", 0, 0, -ENODEV, -ENODEV, 0x00000010, 0xffffffff, 0), | ||
| 1400 | SYSC_QUIRK("sdio", 0, 0, 0x10, -ENODEV, 0x40202301, 0xffff0ff0, 0), | ||
| 1319 | SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0), | 1401 | SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0), |
| 1320 | SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0), | 1402 | SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0), |
| 1321 | SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0), | 1403 | SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40000902, 0xffffffff, 0), |
| 1322 | SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0), | 1404 | SYSC_QUIRK("slimbus", 0, 0, 0x10, -ENODEV, 0x40002903, 0xffffffff, 0), |
| 1323 | SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0), | 1405 | SYSC_QUIRK("spinlock", 0, 0, 0x10, -ENODEV, 0x50020000, 0xffffffff, 0), |
| 1324 | SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0), | 1406 | SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -ENODEV, 0x00000020, 0xffffffff, 0), |
| 1325 | SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0), | 1407 | SYSC_QUIRK("timer32k", 0, 0, 0x4, -ENODEV, 0x00000060, 0xffffffff, 0), |
| 1326 | SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0), | 1408 | SYSC_QUIRK("tpcc", 0, 0, -ENODEV, -ENODEV, 0x40014c00, 0xffffffff, 0), |
| 1327 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), | 1409 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), |
| 1328 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0), | 1410 | SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0), |
| 1329 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), | 1411 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), |
| 1330 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0), | 1412 | SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -ENODEV, 0x50700101, 0xffffffff, 0), |
| 1331 | SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0), | 1413 | SYSC_QUIRK("venc", 0x58003000, 0, -ENODEV, -ENODEV, 0x00000002, 0xffffffff, 0), |
| 1414 | SYSC_QUIRK("vfpe", 0, 0, 0x104, -ENODEV, 0x4d001200, 0xffffffff, 0), | ||
| 1332 | #endif | 1415 | #endif |
| 1333 | }; | 1416 | }; |
| 1334 | 1417 | ||
| @@ -1350,16 +1433,13 @@ static void sysc_init_early_quirks(struct sysc *ddata) · 15 unmodified lines | |||
| 1350 | if (q->base != ddata->module_pa) | 1433 | if (q->base != ddata->module_pa) |
| 1351 | continue; | 1434 | continue; |
| 1352 | 1435 | ||
| 1353 | if (q->rev_offset >= 0 && | 1436 | if (q->rev_offset != ddata->offsets[SYSC_REVISION]) |
| 1354 | q->rev_offset != ddata->offsets[SYSC_REVISION]) | ||
| 1355 | continue; | 1437 | continue; |
| 1356 | 1438 | ||
| 1357 | if (q->sysc_offset >= 0 && | 1439 | if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) |
| 1358 | q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) | ||
| 1359 | continue; | 1440 | continue; |
| 1360 | 1441 | ||
| 1361 | if (q->syss_offset >= 0 && | 1442 | if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) |
| 1362 | q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) | ||
| 1363 | continue; | 1443 | continue; |
| 1364 | 1444 | ||
| 1365 | ddata->name = q->name; | 1445 | ddata->name = q->name; |
| @@ -1379,16 +1459,13 @@ static void sysc_init_revision_quirks(struct sysc *ddata) · 13 unmodified lines | |||
| 1379 | if (q->base && q->base != ddata->module_pa) | 1459 | if (q->base && q->base != ddata->module_pa) |
| 1380 | continue; | 1460 | continue; |
| 1381 | 1461 | ||
| 1382 | if (q->rev_offset >= 0 && | 1462 | if (q->rev_offset != ddata->offsets[SYSC_REVISION]) |
| 1383 | q->rev_offset != ddata->offsets[SYSC_REVISION]) | ||
| 1384 | continue; | 1463 | continue; |
| 1385 | 1464 | ||
| 1386 | if (q->sysc_offset >= 0 && | 1465 | if (q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) |
| 1387 | q->sysc_offset != ddata->offsets[SYSC_SYSCONFIG]) | ||
| 1388 | continue; | 1466 | continue; |
| 1389 | 1467 | ||
| 1390 | if (q->syss_offset >= 0 && | 1468 | if (q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) |
| 1391 | q->syss_offset != ddata->offsets[SYSC_SYSSTATUS]) | ||
| 1392 | continue; | 1469 | continue; |
| 1393 | 1470 | ||
| 1394 | if (q->revision == ddata->revision || | 1471 | if (q->revision == ddata->revision || |
| @@ -1400,6 +1477,128 @@ static void sysc_init_revision_quirks(struct sysc *ddata) · 5 unmodified lines | |||
| 1400 | } | 1477 | } |
| 1401 | } | 1478 | } |
| 1402 | 1479 | ||
| 1480 | /* | ||
| 1481 | * DSS needs dispc outputs disabled to reset modules. Returns mask of | ||
| 1482 | * enabled DSS interrupts. Eventually we may be able to do this on | ||
| 1483 | * dispc init rather than top-level DSS init. | ||
| 1484 | */ | ||
| 1485 | static u32 sysc_quirk_dispc(struct sysc *ddata, int dispc_offset, | ||
| 1486 | bool disable) | ||
| 1487 | { | ||
| 1488 | bool lcd_en, digit_en, lcd2_en = false, lcd3_en = false; | ||
| 1489 | const int lcd_en_mask = BIT(0), digit_en_mask = BIT(1); | ||
| 1490 | int manager_count; | ||
| 1491 | bool framedonetv_irq; | ||
| 1492 | u32 val, irq_mask = 0; | ||
| 1493 | |||
| 1494 | switch (sysc_soc->soc) { | ||
| 1495 | case SOC_2420 ... SOC_3630: | ||
| 1496 | manager_count = 2; | ||
| 1497 | framedonetv_irq = false; | ||
| 1498 | break; | ||
| 1499 | case SOC_4430 ... SOC_4470: | ||
| 1500 | manager_count = 3; | ||
| 1501 | break; | ||
| 1502 | case SOC_5430: | ||
| 1503 | case SOC_DRA7: | ||
| 1504 | manager_count = 4; | ||
| 1505 | break; | ||
| 1506 | case SOC_AM4: | ||
| 1507 | manager_count = 1; | ||
| 1508 | break; | ||
| 1509 | case SOC_UNKNOWN: | ||
| 1510 | default: | ||
| 1511 | return 0; | ||
| 1512 | }; | ||
| 1513 | |||
| 1514 | /* Remap the whole module range to be able to reset dispc outputs */ | ||
| 1515 | devm_iounmap(ddata->dev, ddata->module_va); | ||
| 1516 | ddata->module_va = devm_ioremap(ddata->dev, | ||
| 1517 | ddata->module_pa, | ||
| 1518 | ddata->module_size); | ||
| 1519 | if (!ddata->module_va) | ||
| 1520 | return -EIO; | ||
| 1521 | |||
| 1522 | /* DISP_CONTROL */ | ||
| 1523 | val = sysc_read(ddata, dispc_offset + 0x40); | ||
| 1524 | lcd_en = val & lcd_en_mask; | ||
| 1525 | digit_en = val & digit_en_mask; | ||
| 1526 | if (lcd_en) | ||
| 1527 | irq_mask |= BIT(0); /* FRAMEDONE */ | ||
| 1528 | if (digit_en) { | ||
| 1529 | if (framedonetv_irq) | ||
| 1530 | irq_mask |= BIT(24); /* FRAMEDONETV */ | ||
| 1531 | else | ||
| 1532 | irq_mask |= BIT(2) | BIT(3); /* EVSYNC bits */ | ||
| 1533 | } | ||
| 1534 | if (disable & (lcd_en | digit_en)) | ||
| 1535 | sysc_write(ddata, dispc_offset + 0x40, | ||
| 1536 | val & ~(lcd_en_mask | digit_en_mask)); | ||
| 1537 | |||
| 1538 | if (manager_count <= 2) | ||
| 1539 | return irq_mask; | ||
| 1540 | |||
| 1541 | /* DISPC_CONTROL2 */ | ||
| 1542 | val = sysc_read(ddata, dispc_offset + 0x238); | ||
| 1543 | lcd2_en = val & lcd_en_mask; | ||
| 1544 | if (lcd2_en) | ||
| 1545 | irq_mask |= BIT(22); /* FRAMEDONE2 */ | ||
| 1546 | if (disable && lcd2_en) | ||
| 1547 | sysc_write(ddata, dispc_offset + 0x238, | ||
| 1548 | val & ~lcd_en_mask); | ||
| 1549 | |||
| 1550 | if (manager_count <= 3) | ||
| 1551 | return irq_mask; | ||
| 1552 | |||
| 1553 | /* DISPC_CONTROL3 */ | ||
| 1554 | val = sysc_read(ddata, dispc_offset + 0x848); | ||
| 1555 | lcd3_en = val & lcd_en_mask; | ||
| 1556 | if (lcd3_en) | ||
| 1557 | irq_mask |= BIT(30); /* FRAMEDONE3 */ | ||
| 1558 | if (disable && lcd3_en) | ||
| 1559 | sysc_write(ddata, dispc_offset + 0x848, | ||
| 1560 | val & ~lcd_en_mask); | ||
| 1561 | |||
| 1562 | return irq_mask; | ||
| 1563 | } | ||
| 1564 | |||
| 1565 | /* DSS needs child outputs disabled and SDI registers cleared for reset */ | ||
| 1566 | static void sysc_pre_reset_quirk_dss(struct sysc *ddata) | ||
| 1567 | { | ||
| 1568 | const int dispc_offset = 0x1000; | ||
| 1569 | int error; | ||
| 1570 | u32 irq_mask, val; | ||
| 1571 | |||
| 1572 | /* Get enabled outputs */ | ||
| 1573 | irq_mask = sysc_quirk_dispc(ddata, dispc_offset, false); | ||
| 1574 | if (!irq_mask) | ||
| 1575 | return; | ||
| 1576 | |||
| 1577 | /* Clear IRQSTATUS */ | ||
| 1578 | sysc_write(ddata, dispc_offset + 0x18, irq_mask); | ||
| 1579 | |||
| 1580 | /* Disable outputs */ | ||
| 1581 | val = sysc_quirk_dispc(ddata, dispc_offset, true); | ||
| 1582 | |||
| 1583 | /* Poll IRQSTATUS */ | ||
| 1584 | error = readl_poll_timeout(ddata->module_va + dispc_offset + 0x18, | ||
| 1585 | val, val != irq_mask, 100, 50); | ||
| 1586 | if (error) | ||
| 1587 | dev_warn(ddata->dev, "%s: timed out %08x !+ %08x\n", | ||
| 1588 | __func__, val, irq_mask); | ||
| 1589 | |||
| 1590 | if (sysc_soc->soc == SOC_3430) { | ||
| 1591 | /* Clear DSS_SDI_CONTROL */ | ||
| 1592 | sysc_write(ddata, 0x44, 0); | ||
| 1593 | |||
| 1594 | /* Clear DSS_PLL_CONTROL */ | ||
| 1595 | sysc_write(ddata, 0x48, 0); | ||
| 1596 | } | ||
| 1597 | |||
| 1598 | /* Clear DSS_CONTROL to switch DSS clock sources to PRCM if not */ | ||
| 1599 | sysc_write(ddata, 0x40, 0); | ||
| 1600 | } | ||
| 1601 | |||
| 1403 | /* 1-wire needs module's internal clocks enabled for reset */ | 1602 | /* 1-wire needs module's internal clocks enabled for reset */ |
| 1404 | static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata) | 1603 | static void sysc_pre_reset_quirk_hdq1w(struct sysc *ddata) |
| 1405 | { | 1604 | { |
| @@ -1419,7 +1618,7 @@ static void sysc_module_enable_quirk_aess(struct sysc *ddata) · 13 unmodified lines | |||
| 1419 | sysc_write(ddata, offset, 1); | 1618 | sysc_write(ddata, offset, 1); |
| 1420 | } | 1619 | } |
| 1421 | 1620 | ||
| 1422 | /* I2C needs extra enable bit toggling for reset */ | 1621 | /* I2C needs to be disabled for reset */ |
| 1423 | static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable) | 1622 | static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable) |
| 1424 | { | 1623 | { |
| 1425 | int offset; | 1624 | int offset; |
| @@ -1440,14 +1639,48 @@ static void sysc_clk_quirk_i2c(struct sysc *ddata, bool enable) · 14 unmodified lines | |||
| 1440 | sysc_write(ddata, offset, val); | 1639 | sysc_write(ddata, offset, val); |
| 1441 | } | 1640 | } |
| 1442 | 1641 | ||
| 1443 | static void sysc_clk_enable_quirk_i2c(struct sysc *ddata) | 1642 | static void sysc_pre_reset_quirk_i2c(struct sysc *ddata) |
| 1643 | { | ||
| 1644 | sysc_clk_quirk_i2c(ddata, false); | ||
| 1645 | } | ||
| 1646 | |||
| 1647 | static void sysc_post_reset_quirk_i2c(struct sysc *ddata) | ||
| 1444 | { | 1648 | { |
| 1445 | sysc_clk_quirk_i2c(ddata, true); | 1649 | sysc_clk_quirk_i2c(ddata, true); |
| 1446 | } | 1650 | } |
| 1447 | 1651 | ||
| 1448 | static void sysc_clk_disable_quirk_i2c(struct sysc *ddata) | 1652 | /* RTC on am3 and 4 needs to be unlocked and locked for sysconfig */ |
| 1653 | static void sysc_quirk_rtc(struct sysc *ddata, bool lock) | ||
| 1449 | { | 1654 | { |
| 1450 | sysc_clk_quirk_i2c(ddata, false); | 1655 | u32 val, kick0_val = 0, kick1_val = 0; |
| 1656 | unsigned long flags; | ||
| 1657 | int error; | ||
| 1658 | |||
| 1659 | if (!lock) { | ||
| 1660 | kick0_val = 0x83e70b13; | ||
| 1661 | kick1_val = 0x95a4f1e0; | ||
| 1662 | } | ||
| 1663 | |||
| 1664 | local_irq_save(flags); | ||
| 1665 | /* RTC_STATUS BUSY bit may stay active for 1/32768 seconds (~30 usec) */ | ||
| 1666 | error = readl_poll_timeout(ddata->module_va + 0x44, val, | ||
| 1667 | !(val & BIT(0)), 100, 50); | ||
| 1668 | if (error) | ||
| 1669 | dev_warn(ddata->dev, "rtc busy timeout\n"); | ||
| 1670 | /* Now we have ~15 microseconds to read/write various registers */ | ||
| 1671 | sysc_write(ddata, 0x6c, kick0_val); | ||
| 1672 | sysc_write(ddata, 0x70, kick1_val); | ||
| 1673 | local_irq_restore(flags); | ||
| 1674 | } | ||
| 1675 | |||
| 1676 | static void sysc_module_unlock_quirk_rtc(struct sysc *ddata) | ||
| 1677 | { | ||
| 1678 | sysc_quirk_rtc(ddata, false); | ||
| 1679 | } | ||
| 1680 | |||
| 1681 | static void sysc_module_lock_quirk_rtc(struct sysc *ddata) | ||
| 1682 | { | ||
| 1683 | sysc_quirk_rtc(ddata, true); | ||
| 1451 | } | 1684 | } |
| 1452 | 1685 | ||
| 1453 | /* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */ | 1686 | /* 36xx SGX needs a quirk for to bypass OCP IPG interrupt logic */ |
| @@ -1483,20 +1716,30 @@ static void sysc_reset_done_quirk_wdt(struct sysc *ddata) · 29 unmodified lines | |||
| 1483 | dev_warn(ddata->dev, "wdt disable step2 failed\n"); | 1716 | dev_warn(ddata->dev, "wdt disable step2 failed\n"); |
| 1484 | } | 1717 | } |
| 1485 | 1718 | ||
| 1719 | /* PRUSS needs to set MSTANDBY_INIT inorder to idle properly */ | ||
| 1720 | static void sysc_module_disable_quirk_pruss(struct sysc *ddata) | ||
| 1721 | { | ||
| 1722 | u32 reg; | ||
| 1723 | |||
| 1724 | reg = sysc_read(ddata, ddata->offsets[SYSC_SYSCONFIG]); | ||
| 1725 | reg |= SYSC_PRUSS_STANDBY_INIT; | ||
| 1726 | sysc_write(ddata, ddata->offsets[SYSC_SYSCONFIG], reg); | ||
| 1727 | } | ||
| 1728 | |||
| 1486 | static void sysc_init_module_quirks(struct sysc *ddata) | 1729 | static void sysc_init_module_quirks(struct sysc *ddata) |
| 1487 | { | 1730 | { |
| 1488 | if (ddata->legacy_mode || !ddata->name) | 1731 | if (ddata->legacy_mode || !ddata->name) |
| 1489 | return; | 1732 | return; |
| 1490 | 1733 | ||
| 1491 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) { | 1734 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_HDQ1W) { |
| 1492 | ddata->clk_disable_quirk = sysc_pre_reset_quirk_hdq1w; | 1735 | ddata->pre_reset_quirk = sysc_pre_reset_quirk_hdq1w; |
| 1493 | 1736 | ||
| 1494 | return; | 1737 | return; |
| 1495 | } | 1738 | } |
| 1496 | 1739 | ||
| 1497 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) { | 1740 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_I2C) { |
| 1498 | ddata->clk_enable_quirk = sysc_clk_enable_quirk_i2c; | 1741 | ddata->pre_reset_quirk = sysc_pre_reset_quirk_i2c; |
| 1499 | ddata->clk_disable_quirk = sysc_clk_disable_quirk_i2c; | 1742 | ddata->post_reset_quirk = sysc_post_reset_quirk_i2c; |
| 1500 | 1743 | ||
| 1501 | return; | 1744 | return; |
| 1502 | } | 1745 | } |
| @@ -1504,6 +1747,16 @@ static void sysc_init_module_quirks(struct sysc *ddata) · 1 unmodified line | |||
| 1504 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS) | 1747 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_AESS) |
| 1505 | ddata->module_enable_quirk = sysc_module_enable_quirk_aess; | 1748 | ddata->module_enable_quirk = sysc_module_enable_quirk_aess; |
| 1506 | 1749 | ||
| 1750 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_DSS_RESET) | ||
| 1751 | ddata->pre_reset_quirk = sysc_pre_reset_quirk_dss; | ||
| 1752 | |||
| 1753 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_RTC_UNLOCK) { | ||
| 1754 | ddata->module_unlock_quirk = sysc_module_unlock_quirk_rtc; | ||
| 1755 | ddata->module_lock_quirk = sysc_module_lock_quirk_rtc; | ||
| 1756 | |||
| 1757 | return; | ||
| 1758 | } | ||
| 1759 | |||
| 1507 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX) | 1760 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_SGX) |
| 1508 | ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; | 1761 | ddata->module_enable_quirk = sysc_module_enable_quirk_sgx; |
| 1509 | 1762 | ||
| @@ -1511,6 +1764,9 @@ static void sysc_init_module_quirks(struct sysc *ddata) · 1 unmodified line | |||
| 1511 | ddata->reset_done_quirk = sysc_reset_done_quirk_wdt; | 1764 | ddata->reset_done_quirk = sysc_reset_done_quirk_wdt; |
| 1512 | ddata->module_disable_quirk = sysc_reset_done_quirk_wdt; | 1765 | ddata->module_disable_quirk = sysc_reset_done_quirk_wdt; |
| 1513 | } | 1766 | } |
| 1767 | |||
| 1768 | if (ddata->cfg.quirks & SYSC_MODULE_QUIRK_PRUSS) | ||
| 1769 | ddata->module_disable_quirk = sysc_module_disable_quirk_pruss; | ||
| 1514 | } | 1770 | } |
| 1515 | 1771 | ||
| 1516 | static int sysc_clockdomain_init(struct sysc *ddata) | 1772 | static int sysc_clockdomain_init(struct sysc *ddata) |
| @@ -1572,7 +1828,7 @@ static int sysc_reset(struct sysc *ddata) · 55 unmodified lines | |||
| 1572 | sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; | 1828 | sysc_offset = ddata->offsets[SYSC_SYSCONFIG]; |
| 1573 | syss_offset = ddata->offsets[SYSC_SYSSTATUS]; | 1829 | syss_offset = ddata->offsets[SYSC_SYSSTATUS]; |
| 1574 | 1830 | ||
| 1575 | if (ddata->legacy_mode || sysc_offset < 0 || | 1831 | if (ddata->legacy_mode || |
| 1576 | ddata->cap->regbits->srst_shift < 0 || | 1832 | ddata->cap->regbits->srst_shift < 0 || |
| 1577 | ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) | 1833 | ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) |
| 1578 | return 0; | 1834 | return 0; |
| @@ -1584,19 +1840,21 @@ static int sysc_reset(struct sysc *ddata) · 5 unmodified lines | |||
| 1584 | else | 1840 | else |
| 1585 | syss_done = ddata->cfg.syss_mask; | 1841 | syss_done = ddata->cfg.syss_mask; |
| 1586 | 1842 | ||
| 1587 | if (ddata->clk_disable_quirk) | 1843 | if (ddata->pre_reset_quirk) |
| 1588 | ddata->clk_disable_quirk(ddata); | 1844 | ddata->pre_reset_quirk(ddata); |
| 1589 | 1845 | ||
| 1590 | sysc_val = sysc_read_sysconfig(ddata); | 1846 | if (sysc_offset >= 0) { |
| 1591 | sysc_val |= sysc_mask; | 1847 | sysc_val = sysc_read_sysconfig(ddata); |
| 1592 | sysc_write(ddata, sysc_offset, sysc_val); | 1848 | sysc_val |= sysc_mask; |
| 1849 | sysc_write(ddata, sysc_offset, sysc_val); | ||
| 1850 | } | ||
| 1593 | 1851 | ||
| 1594 | if (ddata->cfg.srst_udelay) | 1852 | if (ddata->cfg.srst_udelay) |
| 1595 | usleep_range(ddata->cfg.srst_udelay, | 1853 | usleep_range(ddata->cfg.srst_udelay, |
| 1596 | ddata->cfg.srst_udelay * 2); | 1854 | ddata->cfg.srst_udelay * 2); |
| 1597 | 1855 | ||
| 1598 | if (ddata->clk_enable_quirk) | 1856 | if (ddata->post_reset_quirk) |
| 1599 | ddata->clk_enable_quirk(ddata); | 1857 | ddata->post_reset_quirk(ddata); |
| 1600 | 1858 | ||
| 1601 | /* Poll on reset status */ | 1859 | /* Poll on reset status */ |
| 1602 | if (syss_offset >= 0) { | 1860 | if (syss_offset >= 0) { |
| @@ -2314,6 +2572,16 @@ static const struct sysc_capabilities sysc_dra7_mcan = { · 711 unmodified lines | |||
| 2314 | .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED, | 2572 | .mod_quirks = SYSS_QUIRK_RESETDONE_INVERTED, |
| 2315 | }; | 2573 | }; |
| 2316 | 2574 | ||
| 2575 | /* | ||
| 2576 | * PRUSS found on some AM33xx, AM437x and AM57xx SoCs | ||
| 2577 | */ | ||
| 2578 | static const struct sysc_capabilities sysc_pruss = { | ||
| 2579 | .type = TI_SYSC_PRUSS, | ||
| 2580 | .sysc_mask = SYSC_PRUSS_STANDBY_INIT | SYSC_PRUSS_SUB_MWAIT, | ||
| 2581 | .regbits = &sysc_regbits_omap4_simple, | ||
| 2582 | .mod_quirks = SYSC_MODULE_QUIRK_PRUSS, | ||
| 2583 | }; | ||
| 2584 | |||
| 2317 | static int sysc_init_pdata(struct sysc *ddata) | 2585 | static int sysc_init_pdata(struct sysc *ddata) |
| 2318 | { | 2586 | { |
| 2319 | struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); | 2587 | struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); |
| @@ -2387,6 +2655,154 @@ static void ti_sysc_idle(struct work_struct *work) · 67 unmodified lines | |||
| 2387 | pm_runtime_put_sync(ddata->dev); | 2655 | pm_runtime_put_sync(ddata->dev); |
| 2388 | } | 2656 | } |
| 2389 | 2657 | ||
| 2658 | /* | ||
| 2659 | * SoC model and features detection. Only needed for SoCs that need | ||
| 2660 | * special handling for quirks, no need to list others. | ||
| 2661 | */ | ||
| 2662 | static const struct soc_device_attribute sysc_soc_match[] = { | ||
| 2663 | SOC_FLAG("OMAP242*", SOC_2420), | ||
| 2664 | SOC_FLAG("OMAP243*", SOC_2430), | ||
| 2665 | SOC_FLAG("OMAP3[45]*", SOC_3430), | ||
| 2666 | SOC_FLAG("OMAP3[67]*", SOC_3630), | ||
| 2667 | SOC_FLAG("OMAP443*", SOC_4430), | ||
| 2668 | SOC_FLAG("OMAP446*", SOC_4460), | ||
| 2669 | SOC_FLAG("OMAP447*", SOC_4470), | ||
| 2670 | SOC_FLAG("OMAP54*", SOC_5430), | ||
| 2671 | SOC_FLAG("AM433", SOC_AM3), | ||
| 2672 | SOC_FLAG("AM43*", SOC_AM4), | ||
| 2673 | SOC_FLAG("DRA7*", SOC_DRA7), | ||
| 2674 | |||
| 2675 | { /* sentinel */ }, | ||
| 2676 | }; | ||
| 2677 | |||
| 2678 | /* | ||
| 2679 | * List of SoCs variants with disabled features. By default we assume all | ||
| 2680 | * devices in the device tree are available so no need to list those SoCs. | ||
| 2681 | */ | ||
| 2682 | static const struct soc_device_attribute sysc_soc_feat_match[] = { | ||
| 2683 | /* OMAP3430/3530 and AM3517 variants with some accelerators disabled */ | ||
| 2684 | SOC_FLAG("AM3505", DIS_SGX), | ||
| 2685 | SOC_FLAG("OMAP3525", DIS_SGX), | ||
| 2686 | SOC_FLAG("OMAP3515", DIS_IVA | DIS_SGX), | ||
| 2687 | SOC_FLAG("OMAP3503", DIS_ISP | DIS_IVA | DIS_SGX), | ||
| 2688 | |||
| 2689 | /* OMAP3630/DM3730 variants with some accelerators disabled */ | ||
| 2690 | SOC_FLAG("AM3703", DIS_IVA | DIS_SGX), | ||
| 2691 | SOC_FLAG("DM3725", DIS_SGX), | ||
| 2692 | SOC_FLAG("OMAP3611", DIS_ISP | DIS_IVA | DIS_SGX), | ||
| 2693 | SOC_FLAG("OMAP3615/AM3715", DIS_IVA), | ||
| 2694 | SOC_FLAG("OMAP3621", DIS_ISP), | ||
| 2695 | |||
| 2696 | { /* sentinel */ }, | ||
| 2697 | }; | ||
| 2698 | |||
| 2699 | static int sysc_add_disabled(unsigned long base) | ||
| 2700 | { | ||
| 2701 | struct sysc_address *disabled_module; | ||
| 2702 | |||
| 2703 | disabled_module = kzalloc(sizeof(*disabled_module), GFP_KERNEL); | ||
| 2704 | if (!disabled_module) | ||
| 2705 | return -ENOMEM; | ||
| 2706 | |||
| 2707 | disabled_module->base = base; | ||
| 2708 | |||
| 2709 | mutex_lock(&sysc_soc->list_lock); | ||
| 2710 | list_add(&disabled_module->node, &sysc_soc->disabled_modules); | ||
| 2711 | mutex_unlock(&sysc_soc->list_lock); | ||
| 2712 | |||
| 2713 | return 0; | ||
| 2714 | } | ||
| 2715 | |||
| 2716 | /* | ||
| 2717 | * One time init to detect the booted SoC and disable unavailable features. | ||
| 2718 | * Note that we initialize static data shared across all ti-sysc instances | ||
| 2719 | * so ddata is only used for SoC type. This can be called from module_init | ||
| 2720 | * once we no longer need to rely on platform data. | ||
| 2721 | */ | ||
| 2722 | static int sysc_init_soc(struct sysc *ddata) | ||
| 2723 | { | ||
| 2724 | const struct soc_device_attribute *match; | ||
| 2725 | struct ti_sysc_platform_data *pdata; | ||
| 2726 | unsigned long features = 0; | ||
| 2727 | |||
| 2728 | if (sysc_soc) | ||
| 2729 | return 0; | ||
| 2730 | |||
| 2731 | sysc_soc = kzalloc(sizeof(*sysc_soc), GFP_KERNEL); | ||
| 2732 | if (!sysc_soc) | ||
| 2733 | return -ENOMEM; | ||
| 2734 | |||
| 2735 | mutex_init(&sysc_soc->list_lock); | ||
| 2736 | INIT_LIST_HEAD(&sysc_soc->disabled_modules); | ||
| 2737 | sysc_soc->general_purpose = true; | ||
| 2738 | |||
| 2739 | pdata = dev_get_platdata(ddata->dev); | ||
| 2740 | if (pdata && pdata->soc_type_gp) | ||
| 2741 | sysc_soc->general_purpose = pdata->soc_type_gp(); | ||
| 2742 | |||
| 2743 | match = soc_device_match(sysc_soc_match); | ||
| 2744 | if (match && match->data) | ||
| 2745 | sysc_soc->soc = (int)match->data; | ||
| 2746 | |||
| 2747 | match = soc_device_match(sysc_soc_feat_match); | ||
| 2748 | if (!match) | ||
| 2749 | return 0; | ||
| 2750 | |||
| 2751 | if (match->data) | ||
| 2752 | features = (unsigned long)match->data; | ||
| 2753 | |||
| 2754 | /* | ||
| 2755 | * Add disabled devices to the list based on the module base. | ||
| 2756 | * Note that this must be done before we attempt to access the | ||
| 2757 | * device and have module revision checks working. | ||
| 2758 | */ | ||
| 2759 | if (features & DIS_ISP) | ||
| 2760 | sysc_add_disabled(0x480bd400); | ||
| 2761 | if (features & DIS_IVA) | ||
| 2762 | sysc_add_disabled(0x5d000000); | ||
| 2763 | if (features & DIS_SGX) | ||
| 2764 | sysc_add_disabled(0x50000000); | ||
| 2765 | |||
| 2766 | return 0; | ||
| 2767 | } | ||
| 2768 | |||
| 2769 | static void sysc_cleanup_soc(void) | ||
| 2770 | { | ||
| 2771 | struct sysc_address *disabled_module; | ||
| 2772 | struct list_head *pos, *tmp; | ||
| 2773 | |||
| 2774 | if (!sysc_soc) | ||
| 2775 | return; | ||
| 2776 | |||
| 2777 | mutex_lock(&sysc_soc->list_lock); | ||
| 2778 | list_for_each_safe(pos, tmp, &sysc_soc->disabled_modules) { | ||
| 2779 | disabled_module = list_entry(pos, struct sysc_address, node); | ||
| 2780 | list_del(pos); | ||
| 2781 | kfree(disabled_module); | ||
| 2782 | } | ||
| 2783 | mutex_unlock(&sysc_soc->list_lock); | ||
| 2784 | } | ||
| 2785 | |||
| 2786 | static int sysc_check_disabled_devices(struct sysc *ddata) | ||
| 2787 | { | ||
| 2788 | struct sysc_address *disabled_module; | ||
| 2789 | struct list_head *pos; | ||
| 2790 | int error = 0; | ||
| 2791 | |||
| 2792 | mutex_lock(&sysc_soc->list_lock); | ||
| 2793 | list_for_each(pos, &sysc_soc->disabled_modules) { | ||
| 2794 | disabled_module = list_entry(pos, struct sysc_address, node); | ||
| 2795 | if (ddata->module_pa == disabled_module->base) { | ||
| 2796 | dev_dbg(ddata->dev, "module disabled for this SoC\n"); | ||
| 2797 | error = -ENODEV; | ||
| 2798 | break; | ||
| 2799 | } | ||
| 2800 | } | ||
| 2801 | mutex_unlock(&sysc_soc->list_lock); | ||
| 2802 | |||
| 2803 | return error; | ||
| 2804 | } | ||
| 2805 | |||
| 2390 | static const struct of_device_id sysc_match_table[] = { | 2806 | static const struct of_device_id sysc_match_table[] = { |
| 2391 | { .compatible = "simple-bus", }, | 2807 | { .compatible = "simple-bus", }, |
| 2392 | { /* sentinel */ }, | 2808 | { /* sentinel */ }, |
| @@ -2405,6 +2821,10 @@ static int sysc_probe(struct platform_device *pdev) · 12 unmodified lines | |||
| 2405 | ddata->dev = &pdev->dev; | 2821 | ddata->dev = &pdev->dev; |
| 2406 | platform_set_drvdata(pdev, ddata); | 2822 | platform_set_drvdata(pdev, ddata); |
| 2407 | 2823 | ||
| 2824 | error = sysc_init_soc(ddata); | ||
| 2825 | if (error) | ||
| 2826 | return error; | ||
| 2827 | |||
| 2408 | error = sysc_init_match(ddata); | 2828 | error = sysc_init_match(ddata); |
| 2409 | if (error) | 2829 | if (error) |
| 2410 | return error; | 2830 | return error; |
| @@ -2435,6 +2855,10 @@ static int sysc_probe(struct platform_device *pdev) · 24 unmodified lines | |||
| 2435 | 2855 | ||
| 2436 | sysc_init_early_quirks(ddata); | 2856 | sysc_init_early_quirks(ddata); |
| 2437 | 2857 | ||
| 2858 | error = sysc_check_disabled_devices(ddata); | ||
| 2859 | if (error) | ||
| 2860 | return error; | ||
| 2861 | |||
| 2438 | error = sysc_get_clocks(ddata); | 2862 | error = sysc_get_clocks(ddata); |
| 2439 | if (error) | 2863 | if (error) |
| 2440 | return error; | 2864 | return error; |
| @@ -2539,6 +2963,7 @@ static const struct of_device_id sysc_match[] = { · 98 unmodified lines | |||
| 2539 | { .compatible = "ti,sysc-usb-host-fs", | 2963 | { .compatible = "ti,sysc-usb-host-fs", |
| 2540 | .data = &sysc_omap4_usb_host_fs, }, | 2964 | .data = &sysc_omap4_usb_host_fs, }, |
| 2541 | { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, | 2965 | { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, |
| 2966 | { .compatible = "ti,sysc-pruss", .data = &sysc_pruss, }, | ||
| 2542 | { }, | 2967 | { }, |
| 2543 | }; | 2968 | }; |
| 2544 | MODULE_DEVICE_TABLE(of, sysc_match); | 2969 | MODULE_DEVICE_TABLE(of, sysc_match); |
| @@ -2565,6 +2990,7 @@ static void __exit sysc_exit(void) · 20 unmodified lines | |||
| 2565 | { | 2990 | { |
| 2566 | bus_unregister_notifier(&platform_bus_type, &sysc_nb); | 2991 | bus_unregister_notifier(&platform_bus_type, &sysc_nb); |
| 2567 | platform_driver_unregister(&sysc_driver); | 2992 | platform_driver_unregister(&sysc_driver); |
| 2993 | sysc_cleanup_soc(); | ||
| 2568 | } | 2994 | } |
| 2569 | module_exit(sysc_exit); | 2995 | module_exit(sysc_exit); |
| 2570 | 2996 | ||
| @@ -1,6 +1,7 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o | 2 | obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o |
| 3 | scmi-bus-y = bus.o | 3 | scmi-bus-y = bus.o |
| 4 | scmi-driver-y = driver.o | 4 | scmi-driver-y = driver.o |
| 5 | scmi-transport-y = mailbox.o shmem.o | ||
| 5 | scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o | 6 | scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o |
| 6 | obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o | 7 | obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o |
| @@ -33,8 +33,8 @@ enum scmi_common_cmd { · 32 unmodified lines | |||
| 33 | /** | 33 | /** |
| 34 | * struct scmi_msg_resp_prot_version - Response for a message | 34 | * struct scmi_msg_resp_prot_version - Response for a message |
| 35 | * | 35 | * |
| 36 | * @major_version: Major version of the ABI that firmware supports | ||
| 37 | * @minor_version: Minor version of the ABI that firmware supports | 36 | * @minor_version: Minor version of the ABI that firmware supports |
| 37 | * @major_version: Major version of the ABI that firmware supports | ||
| 38 | * | 38 | * |
| 39 | * In general, ABI version changes follow the rule that minor version increments | 39 | * In general, ABI version changes follow the rule that minor version increments |
| 40 | * are backward compatible. Major revision changes in ABI may not be | 40 | * are backward compatible. Major revision changes in ABI may not be |
| @@ -47,6 +47,19 @@ struct scmi_msg_resp_prot_version { · 6 unmodified lines | |||
| 47 | __le16 major_version; | 47 | __le16 major_version; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | #define MSG_ID_MASK GENMASK(7, 0) | ||
| 51 | #define MSG_XTRACT_ID(hdr) FIELD_GET(MSG_ID_MASK, (hdr)) | ||
| 52 | #define MSG_TYPE_MASK GENMASK(9, 8) | ||
| 53 | #define MSG_XTRACT_TYPE(hdr) FIELD_GET(MSG_TYPE_MASK, (hdr)) | ||
| 54 | #define MSG_TYPE_COMMAND 0 | ||
| 55 | #define MSG_TYPE_DELAYED_RESP 2 | ||
| 56 | #define MSG_TYPE_NOTIFICATION 3 | ||
| 57 | #define MSG_PROTOCOL_ID_MASK GENMASK(17, 10) | ||
| 58 | #define MSG_XTRACT_PROT_ID(hdr) FIELD_GET(MSG_PROTOCOL_ID_MASK, (hdr)) | ||
| 59 | #define MSG_TOKEN_ID_MASK GENMASK(27, 18) | ||
| 60 | #define MSG_XTRACT_TOKEN(hdr) FIELD_GET(MSG_TOKEN_ID_MASK, (hdr)) | ||
| 61 | #define MSG_TOKEN_MAX (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1) | ||
| 62 | |||
| 50 | /** | 63 | /** |
| 51 | * struct scmi_msg_hdr - Message(Tx/Rx) header | 64 | * struct scmi_msg_hdr - Message(Tx/Rx) header |
| 52 | * | 65 | * |
| @@ -67,6 +80,33 @@ struct scmi_msg_hdr { · 14 unmodified lines | |||
| 67 | bool poll_completion; | 80 | bool poll_completion; |
| 68 | }; | 81 | }; |
| 69 | 82 | ||
| 83 | /** | ||
| 84 | * pack_scmi_header() - packs and returns 32-bit header | ||
| 85 | * | ||
| 86 | * @hdr: pointer to header containing all the information on message id, | ||
| 87 | * protocol id and sequence id. | ||
| 88 | * | ||
| 89 | * Return: 32-bit packed message header to be sent to the platform. | ||
| 90 | */ | ||
| 91 | static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) | ||
| 92 | { | ||
| 93 | return FIELD_PREP(MSG_ID_MASK, hdr->id) | | ||
| 94 | FIELD_PREP(MSG_TOKEN_ID_MASK, hdr->seq) | | ||
| 95 | FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id); | ||
| 96 | } | ||
| 97 | |||
| 98 | /** | ||
| 99 | * unpack_scmi_header() - unpacks and records message and protocol id | ||
| 100 | * | ||
| 101 | * @msg_hdr: 32-bit packed message header sent from the platform | ||
| 102 | * @hdr: pointer to header to fetch message and protocol id. | ||
| 103 | */ | ||
| 104 | static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr) | ||
| 105 | { | ||
| 106 | hdr->id = MSG_XTRACT_ID(msg_hdr); | ||
| 107 | hdr->protocol_id = MSG_XTRACT_PROT_ID(msg_hdr); | ||
| 108 | } | ||
| 109 | |||
| 70 | /** | 110 | /** |
| 71 | * struct scmi_msg - Message(Tx/Rx) structure | 111 | * struct scmi_msg - Message(Tx/Rx) structure |
| 72 | * | 112 | * |
| @@ -88,7 +128,7 @@ struct scmi_msg { · 15 unmodified lines | |||
| 88 | * message. If request-ACK protocol is used, we can reuse the same | 128 | * message. If request-ACK protocol is used, we can reuse the same |
| 89 | * buffer for the rx path as we use for the tx path. | 129 | * buffer for the rx path as we use for the tx path. |
| 90 | * @done: command message transmit completion event | 130 | * @done: command message transmit completion event |
| 91 | * @async: pointer to delayed response message received event completion | 131 | * @async_done: pointer to delayed response message received event completion |
| 92 | */ | 132 | */ |
| 93 | struct scmi_xfer { | 133 | struct scmi_xfer { |
| 94 | int transfer_id; | 134 | int transfer_id; |
| @@ -113,3 +153,74 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle, · 18 unmodified lines | |||
| 113 | u8 *prot_imp); | 153 | u8 *prot_imp); |
| 114 | 154 | ||
| 115 | int scmi_base_protocol_init(struct scmi_handle *h); | 155 | int scmi_base_protocol_init(struct scmi_handle *h); |
| 156 | |||
| 157 | /* SCMI Transport */ | ||
| 158 | /** | ||
| 159 | * struct scmi_chan_info - Structure representing a SCMI channel information | ||
| 160 | * | ||
| 161 | * @dev: Reference to device in the SCMI hierarchy corresponding to this | ||
| 162 | * channel | ||
| 163 | * @handle: Pointer to SCMI entity handle | ||
| 164 | * @transport_info: Transport layer related information | ||
| 165 | */ | ||
| 166 | struct scmi_chan_info { | ||
| 167 | struct device *dev; | ||
| 168 | struct scmi_handle *handle; | ||
| 169 | void *transport_info; | ||
| 170 | }; | ||
| 171 | |||
| 172 | /** | ||
| 173 | * struct scmi_transport_ops - Structure representing a SCMI transport ops | ||
| 174 | * | ||
| 175 | * @chan_available: Callback to check if channel is available or not | ||
| 176 | * @chan_setup: Callback to allocate and setup a channel | ||
| 177 | * @chan_free: Callback to free a channel | ||
| 178 | * @send_message: Callback to send a message | ||
| 179 | * @mark_txdone: Callback to mark tx as done | ||
| 180 | * @fetch_response: Callback to fetch response | ||
| 181 | * @poll_done: Callback to poll transfer status | ||
| 182 | */ | ||
| 183 | struct scmi_transport_ops { | ||
| 184 | bool (*chan_available)(struct device *dev, int idx); | ||
| 185 | int (*chan_setup)(struct scmi_chan_info *cinfo, struct device *dev, | ||
| 186 | bool tx); | ||
| 187 | int (*chan_free)(int id, void *p, void *data); | ||
| 188 | int (*send_message)(struct scmi_chan_info *cinfo, | ||
| 189 | struct scmi_xfer *xfer); | ||
| 190 | void (*mark_txdone)(struct scmi_chan_info *cinfo, int ret); | ||
| 191 | void (*fetch_response)(struct scmi_chan_info *cinfo, | ||
| 192 | struct scmi_xfer *xfer); | ||
| 193 | bool (*poll_done)(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer); | ||
| 194 | }; | ||
| 195 | |||
| 196 | /** | ||
| 197 | * struct scmi_desc - Description of SoC integration | ||
| 198 | * | ||
| 199 | * @ops: Pointer to the transport specific ops structure | ||
| 200 | * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) | ||
| 201 | * @max_msg: Maximum number of messages that can be pending | ||
| 202 | * simultaneously in the system | ||
| 203 | * @max_msg_size: Maximum size of data per message that can be handled. | ||
| 204 | */ | ||
| 205 | struct scmi_desc { | ||
| 206 | struct scmi_transport_ops *ops; | ||
| 207 | int max_rx_timeout_ms; | ||
| 208 | int max_msg; | ||
| 209 | int max_msg_size; | ||
| 210 | }; | ||
| 211 | |||
| 212 | extern const struct scmi_desc scmi_mailbox_desc; | ||
| 213 | |||
| 214 | void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr); | ||
| 215 | void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id); | ||
| 216 | |||
| 217 | /* shmem related declarations */ | ||
| 218 | struct scmi_shared_mem; | ||
| 219 | |||
| 220 | void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, | ||
| 221 | struct scmi_xfer *xfer); | ||
| 222 | u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem); | ||
| 223 | void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, | ||
| 224 | struct scmi_xfer *xfer); | ||
| 225 | bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, | ||
| 226 | struct scmi_xfer *xfer); | ||
| @@ -19,12 +19,10 @@ · 18 unmodified lines | |||
| 19 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/ktime.h> | 21 | #include <linux/ktime.h> |
| 22 | #include <linux/mailbox_client.h> | ||
| 23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| 24 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
| 25 | #include <linux/of_device.h> | 24 | #include <linux/of_device.h> |
| 26 | #include <linux/processor.h> | 25 | #include <linux/processor.h> |
| 27 | #include <linux/semaphore.h> | ||
| 28 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
| 29 | 27 | ||
| 30 | #include "common.h" | 28 | #include "common.h" |
| @@ -32,19 +30,6 @@ · 1 unmodified line | |||
| 32 | #define CREATE_TRACE_POINTS | 30 | #define CREATE_TRACE_POINTS |
| 33 | #include <trace/events/scmi.h> | 31 | #include <trace/events/scmi.h> |
| 34 | 32 | ||
| 35 | #define MSG_ID_MASK GENMASK(7, 0) | ||
| 36 | #define MSG_XTRACT_ID(hdr) FIELD_GET(MSG_ID_MASK, (hdr)) | ||
| 37 | #define MSG_TYPE_MASK GENMASK(9, 8) | ||
| 38 | #define MSG_XTRACT_TYPE(hdr) FIELD_GET(MSG_TYPE_MASK, (hdr)) | ||
| 39 | #define MSG_TYPE_COMMAND 0 | ||
| 40 | #define MSG_TYPE_DELAYED_RESP 2 | ||
| 41 | #define MSG_TYPE_NOTIFICATION 3 | ||
| 42 | #define MSG_PROTOCOL_ID_MASK GENMASK(17, 10) | ||
| 43 | #define MSG_XTRACT_PROT_ID(hdr) FIELD_GET(MSG_PROTOCOL_ID_MASK, (hdr)) | ||
| 44 | #define MSG_TOKEN_ID_MASK GENMASK(27, 18) | ||
| 45 | #define MSG_XTRACT_TOKEN(hdr) FIELD_GET(MSG_TOKEN_ID_MASK, (hdr)) | ||
| 46 | #define MSG_TOKEN_MAX (MSG_XTRACT_TOKEN(MSG_TOKEN_ID_MASK) + 1) | ||
| 47 | |||
| 48 | enum scmi_error_codes { | 33 | enum scmi_error_codes { |
| 49 | SCMI_SUCCESS = 0, /* Success */ | 34 | SCMI_SUCCESS = 0, /* Success */ |
| 50 | SCMI_ERR_SUPPORT = -1, /* Not supported */ | 35 | SCMI_ERR_SUPPORT = -1, /* Not supported */ |
| @@ -82,46 +67,14 @@ struct scmi_xfers_info { · 31 unmodified lines | |||
| 82 | spinlock_t xfer_lock; | 67 | spinlock_t xfer_lock; |
| 83 | }; | 68 | }; |
| 84 | 69 | ||
| 85 | /** | ||
| 86 | * struct scmi_desc - Description of SoC integration | ||
| 87 | * | ||
| 88 | * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) | ||
| 89 | * @max_msg: Maximum number of messages that can be pending | ||
| 90 | * simultaneously in the system | ||
| 91 | * @max_msg_size: Maximum size of data per message that can be handled. | ||
| 92 | */ | ||
| 93 | struct scmi_desc { | ||
| 94 | int max_rx_timeout_ms; | ||
| 95 | int max_msg; | ||
| 96 | int max_msg_size; | ||
| 97 | }; | ||
| 98 | |||
| 99 | /** | ||
| 100 | * struct scmi_chan_info - Structure representing a SCMI channel information | ||
| 101 | * | ||
| 102 | * @cl: Mailbox Client | ||
| 103 | * @chan: Transmit/Receive mailbox channel | ||
| 104 | * @payload: Transmit/Receive mailbox channel payload area | ||
| 105 | * @dev: Reference to device in the SCMI hierarchy corresponding to this | ||
| 106 | * channel | ||
| 107 | * @handle: Pointer to SCMI entity handle | ||
| 108 | */ | ||
| 109 | struct scmi_chan_info { | ||
| 110 | struct mbox_client cl; | ||
| 111 | struct mbox_chan *chan; | ||
| 112 | void __iomem *payload; | ||
| 113 | struct device *dev; | ||
| 114 | struct scmi_handle *handle; | ||
| 115 | }; | ||
| 116 | |||
| 117 | /** | 70 | /** |
| 118 | * struct scmi_info - Structure representing a SCMI instance | 71 | * struct scmi_info - Structure representing a SCMI instance |
| 119 | * | 72 | * |
| 120 | * @dev: Device pointer | 73 | * @dev: Device pointer |
| 121 | * @desc: SoC description for this instance | 74 | * @desc: SoC description for this instance |
| 122 | * @handle: Instance of SCMI handle to send to clients | ||
| 123 | * @version: SCMI revision information containing protocol version, | 75 | * @version: SCMI revision information containing protocol version, |
| 124 | * implementation version and (sub-)vendor identification. | 76 | * implementation version and (sub-)vendor identification. |
| 77 | * @handle: Instance of SCMI handle to send to clients | ||
| 125 | * @tx_minfo: Universal Transmit Message management info | 78 | * @tx_minfo: Universal Transmit Message management info |
| 126 | * @tx_idr: IDR object to map protocol id to Tx channel info pointer | 79 | * @tx_idr: IDR object to map protocol id to Tx channel info pointer |
| 127 | * @rx_idr: IDR object to map protocol id to Rx channel info pointer | 80 | * @rx_idr: IDR object to map protocol id to Rx channel info pointer |
| @@ -143,27 +96,8 @@ struct scmi_info { · 15 unmodified lines | |||
| 143 | int users; | 96 | int users; |
| 144 | }; | 97 | }; |
| 145 | 98 | ||
| 146 | #define client_to_scmi_chan_info(c) container_of(c, struct scmi_chan_info, cl) | ||
| 147 | #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) | 99 | #define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle) |
| 148 | 100 | ||
| 149 | /* | ||
| 150 | * SCMI specification requires all parameters, message headers, return | ||
| 151 | * arguments or any protocol data to be expressed in little endian | ||
| 152 | * format only. | ||
| 153 | */ | ||
| 154 | struct scmi_shared_mem { | ||
| 155 | __le32 reserved; | ||
| 156 | __le32 channel_status; | ||
| 157 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) | ||
| 158 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) | ||
| 159 | __le32 reserved1[2]; | ||
| 160 | __le32 flags; | ||
| 161 | #define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) | ||
| 162 | __le32 length; | ||
| 163 | __le32 msg_header; | ||
| 164 | u8 msg_payload[0]; | ||
| 165 | }; | ||
| 166 | |||
| 167 | static const int scmi_linux_errmap[] = { | 101 | static const int scmi_linux_errmap[] = { |
| 168 | /* better than switch case as long as return value is continuous */ | 102 | /* better than switch case as long as return value is continuous */ |
| 169 | 0, /* SCMI_SUCCESS */ | 103 | 0, /* SCMI_SUCCESS */ |
| @@ -199,77 +133,6 @@ static inline void scmi_dump_header_dbg(struct device *dev, · 29 unmodified lines | |||
| 199 | hdr->id, hdr->seq, hdr->protocol_id); | 133 | hdr->id, hdr->seq, hdr->protocol_id); |
| 200 | } | 134 | } |
| 201 | 135 | ||
| 202 | static void scmi_fetch_response(struct scmi_xfer *xfer, | ||
| 203 | struct scmi_shared_mem __iomem *mem) | ||
| 204 | { | ||
| 205 | xfer->hdr.status = ioread32(mem->msg_payload); | ||
| 206 | /* Skip the length of header and status in payload area i.e 8 bytes */ | ||
| 207 | xfer->rx.len = min_t(size_t, xfer->rx.len, ioread32(&mem->length) - 8); | ||
| 208 | |||
| 209 | /* Take a copy to the rx buffer.. */ | ||
| 210 | memcpy_fromio(xfer->rx.buf, mem->msg_payload + 4, xfer->rx.len); | ||
| 211 | } | ||
| 212 | |||
| 213 | /** | ||
| 214 | * pack_scmi_header() - packs and returns 32-bit header | ||
| 215 | * | ||
| 216 | * @hdr: pointer to header containing all the information on message id, | ||
| 217 | * protocol id and sequence id. | ||
| 218 | * | ||
| 219 | * Return: 32-bit packed message header to be sent to the platform. | ||
| 220 | */ | ||
| 221 | static inline u32 pack_scmi_header(struct scmi_msg_hdr *hdr) | ||
| 222 | { | ||
| 223 | return FIELD_PREP(MSG_ID_MASK, hdr->id) | | ||
| 224 | FIELD_PREP(MSG_TOKEN_ID_MASK, hdr->seq) | | ||
| 225 | FIELD_PREP(MSG_PROTOCOL_ID_MASK, hdr->protocol_id); | ||
| 226 | } | ||
| 227 | |||
| 228 | /** | ||
| 229 | * unpack_scmi_header() - unpacks and records message and protocol id | ||
| 230 | * | ||
| 231 | * @msg_hdr: 32-bit packed message header sent from the platform | ||
| 232 | * @hdr: pointer to header to fetch message and protocol id. | ||
| 233 | */ | ||
| 234 | static inline void unpack_scmi_header(u32 msg_hdr, struct scmi_msg_hdr *hdr) | ||
| 235 | { | ||
| 236 | hdr->id = MSG_XTRACT_ID(msg_hdr); | ||
| 237 | hdr->protocol_id = MSG_XTRACT_PROT_ID(msg_hdr); | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * scmi_tx_prepare() - mailbox client callback to prepare for the transfer | ||
| 242 | * | ||
| 243 | * @cl: client pointer | ||
| 244 | * @m: mailbox message | ||
| 245 | * | ||
| 246 | * This function prepares the shared memory which contains the header and the | ||
| 247 | * payload. | ||
| 248 | */ | ||
| 249 | static void scmi_tx_prepare(struct mbox_client *cl, void *m) | ||
| 250 | { | ||
| 251 | struct scmi_xfer *t = m; | ||
| 252 | struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); | ||
| 253 | struct scmi_shared_mem __iomem *mem = cinfo->payload; | ||
| 254 | |||
| 255 | /* | ||
| 256 | * Ideally channel must be free by now unless OS timeout last | ||
| 257 | * request and platform continued to process the same, wait | ||
| 258 | * until it releases the shared memory, otherwise we may endup | ||
| 259 | * overwriting its response with new message payload or vice-versa | ||
| 260 | */ | ||
| 261 | spin_until_cond(ioread32(&mem->channel_status) & | ||
| 262 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); | ||
| 263 | /* Mark channel busy + clear error */ | ||
| 264 | iowrite32(0x0, &mem->channel_status); | ||
| 265 | iowrite32(t->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, | ||
| 266 | &mem->flags); | ||
| 267 | iowrite32(sizeof(mem->msg_header) + t->tx.len, &mem->length); | ||
| 268 | iowrite32(pack_scmi_header(&t->hdr), &mem->msg_header); | ||
| 269 | if (t->tx.buf) | ||
| 270 | memcpy_toio(mem->msg_payload, t->tx.buf, t->tx.len); | ||
| 271 | } | ||
| 272 | |||
| 273 | /** | 136 | /** |
| 274 | * scmi_xfer_get() - Allocate one message | 137 | * scmi_xfer_get() - Allocate one message |
| 275 | * | 138 | * |
| @@ -338,10 +201,10 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) · 62 unmodified lines | |||
| 338 | } | 201 | } |
| 339 | 202 | ||
| 340 | /** | 203 | /** |
| 341 | * scmi_rx_callback() - mailbox client callback for receive messages | 204 | * scmi_rx_callback() - callback for receiving messages |
| 342 | * | 205 | * |
| 343 | * @cl: client pointer | 206 | * @cinfo: SCMI channel info |
| 344 | * @m: mailbox message | 207 | * @msg_hdr: Message header |
| 345 | * | 208 | * |
| 346 | * Processes one received message to appropriate transfer information and | 209 | * Processes one received message to appropriate transfer information and |
| 347 | * signals completion of the transfer. | 210 | * signals completion of the transfer. |
| @@ -349,21 +212,14 @@ __scmi_xfer_put(struct scmi_xfers_info *minfo, struct scmi_xfer *xfer) · 1 unmodified line | |||
| 349 | * NOTE: This function will be invoked in IRQ context, hence should be | 212 | * NOTE: This function will be invoked in IRQ context, hence should be |
| 350 | * as optimal as possible. | 213 | * as optimal as possible. |
| 351 | */ | 214 | */ |
| 352 | static void scmi_rx_callback(struct mbox_client *cl, void *m) | 215 | void scmi_rx_callback(struct scmi_chan_info *cinfo, u32 msg_hdr) |
| 353 | { | 216 | { |
| 354 | u8 msg_type; | ||
| 355 | u32 msg_hdr; | ||
| 356 | u16 xfer_id; | ||
| 357 | struct scmi_xfer *xfer; | ||
| 358 | struct scmi_chan_info *cinfo = client_to_scmi_chan_info(cl); | ||
| 359 | struct device *dev = cinfo->dev; | ||
| 360 | struct scmi_info *info = handle_to_scmi_info(cinfo->handle); | 217 | struct scmi_info *info = handle_to_scmi_info(cinfo->handle); |
| 361 | struct scmi_xfers_info *minfo = &info->tx_minfo; | 218 | struct scmi_xfers_info *minfo = &info->tx_minfo; |
| 362 | struct scmi_shared_mem __iomem *mem = cinfo->payload; | 219 | u16 xfer_id = MSG_XTRACT_TOKEN(msg_hdr); |
| 363 | 220 | u8 msg_type = MSG_XTRACT_TYPE(msg_hdr); | |
| 364 | msg_hdr = ioread32(&mem->msg_header); | 221 | struct device *dev = cinfo->dev; |
| 365 | msg_type = MSG_XTRACT_TYPE(msg_hdr); | 222 | struct scmi_xfer *xfer; |
| 366 | xfer_id = MSG_XTRACT_TOKEN(msg_hdr); | ||
| 367 | 223 | ||
| 368 | if (msg_type == MSG_TYPE_NOTIFICATION) | 224 | if (msg_type == MSG_TYPE_NOTIFICATION) |
| 369 | return; /* Notifications not yet supported */ | 225 | return; /* Notifications not yet supported */ |
| @@ -378,7 +234,7 @@ static void scmi_rx_callback(struct mbox_client *cl, void *m) · 8 unmodified lines | |||
| 378 | 234 | ||
| 379 | scmi_dump_header_dbg(dev, &xfer->hdr); | 235 | scmi_dump_header_dbg(dev, &xfer->hdr); |
| 380 | 236 | ||
| 381 | scmi_fetch_response(xfer, mem); | 237 | info->desc->ops->fetch_response(cinfo, xfer); |
| 382 | 238 | ||
| 383 | trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id, | 239 | trace_scmi_rx_done(xfer->transfer_id, xfer->hdr.id, |
| 384 | xfer->hdr.protocol_id, xfer->hdr.seq, | 240 | xfer->hdr.protocol_id, xfer->hdr.seq, |
| @@ -403,28 +259,15 @@ void scmi_xfer_put(const struct scmi_handle *handle, struct scmi_xfer *xfer) · 18 unmodified lines | |||
| 403 | __scmi_xfer_put(&info->tx_minfo, xfer); | 259 | __scmi_xfer_put(&info->tx_minfo, xfer); |
| 404 | } | 260 | } |
| 405 | 261 | ||
| 406 | static bool | ||
| 407 | scmi_xfer_poll_done(const struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) | ||
| 408 | { | ||
| 409 | struct scmi_shared_mem __iomem *mem = cinfo->payload; | ||
| 410 | u16 xfer_id = MSG_XTRACT_TOKEN(ioread32(&mem->msg_header)); | ||
| 411 | |||
| 412 | if (xfer->hdr.seq != xfer_id) | ||
| 413 | return false; | ||
| 414 | |||
| 415 | return ioread32(&mem->channel_status) & | ||
| 416 | (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | | ||
| 417 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); | ||
| 418 | } | ||
| 419 | |||
| 420 | #define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC) | 262 | #define SCMI_MAX_POLL_TO_NS (100 * NSEC_PER_USEC) |
| 421 | 263 | ||
| 422 | static bool scmi_xfer_done_no_timeout(const struct scmi_chan_info *cinfo, | 264 | static bool scmi_xfer_done_no_timeout(struct scmi_chan_info *cinfo, |
| 423 | struct scmi_xfer *xfer, ktime_t stop) | 265 | struct scmi_xfer *xfer, ktime_t stop) |
| 424 | { | 266 | { |
| 425 | ktime_t __cur = ktime_get(); | 267 | struct scmi_info *info = handle_to_scmi_info(cinfo->handle); |
| 426 | 268 | ||
| 427 | return scmi_xfer_poll_done(cinfo, xfer) || ktime_after(__cur, stop); | 269 | return info->desc->ops->poll_done(cinfo, xfer) || |
| 270 | ktime_after(ktime_get(), stop); | ||
| 428 | } | 271 | } |
| 429 | 272 | ||
| 430 | /** | 273 | /** |
| @@ -453,29 +296,26 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) · 22 unmodified lines | |||
| 453 | xfer->hdr.protocol_id, xfer->hdr.seq, | 296 | xfer->hdr.protocol_id, xfer->hdr.seq, |
| 454 | xfer->hdr.poll_completion); | 297 | xfer->hdr.poll_completion); |
| 455 | 298 | ||
| 456 | ret = mbox_send_message(cinfo->chan, xfer); | 299 | ret = info->desc->ops->send_message(cinfo, xfer); |
| 457 | if (ret < 0) { | 300 | if (ret < 0) { |
| 458 | dev_dbg(dev, "mbox send fail %d\n", ret); | 301 | dev_dbg(dev, "Failed to send message %d\n", ret); |
| 459 | return ret; | 302 | return ret; |
| 460 | } | 303 | } |
| 461 | 304 | ||
| 462 | /* mbox_send_message returns non-negative value on success, so reset */ | ||
| 463 | ret = 0; | ||
| 464 | |||
| 465 | if (xfer->hdr.poll_completion) { | 305 | if (xfer->hdr.poll_completion) { |
| 466 | ktime_t stop = ktime_add_ns(ktime_get(), SCMI_MAX_POLL_TO_NS); | 306 | ktime_t stop = ktime_add_ns(ktime_get(), SCMI_MAX_POLL_TO_NS); |
| 467 | 307 | ||
| 468 | spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, stop)); | 308 | spin_until_cond(scmi_xfer_done_no_timeout(cinfo, xfer, stop)); |
| 469 | 309 | ||
| 470 | if (ktime_before(ktime_get(), stop)) | 310 | if (ktime_before(ktime_get(), stop)) |
| 471 | scmi_fetch_response(xfer, cinfo->payload); | 311 | info->desc->ops->fetch_response(cinfo, xfer); |
| 472 | else | 312 | else |
| 473 | ret = -ETIMEDOUT; | 313 | ret = -ETIMEDOUT; |
| 474 | } else { | 314 | } else { |
| 475 | /* And we wait for the response. */ | 315 | /* And we wait for the response. */ |
| 476 | timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); | 316 | timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); |
| 477 | if (!wait_for_completion_timeout(&xfer->done, timeout)) { | 317 | if (!wait_for_completion_timeout(&xfer->done, timeout)) { |
| 478 | dev_err(dev, "mbox timed out in resp(caller: %pS)\n", | 318 | dev_err(dev, "timed out in resp(caller: %pS)\n", |
| 479 | (void *)_RET_IP_); | 319 | (void *)_RET_IP_); |
| 480 | ret = -ETIMEDOUT; | 320 | ret = -ETIMEDOUT; |
| 481 | } | 321 | } |
| @@ -484,13 +324,8 @@ int scmi_do_xfer(const struct scmi_handle *handle, struct scmi_xfer *xfer) · 2 unmodified lines | |||
| 484 | if (!ret && xfer->hdr.status) | 324 | if (!ret && xfer->hdr.status) |
| 485 | ret = scmi_to_linux_errno(xfer->hdr.status); | 325 | ret = scmi_to_linux_errno(xfer->hdr.status); |
| 486 | 326 | ||
| 487 | /* | 327 | if (info->desc->ops->mark_txdone) |
| 488 | * NOTE: we might prefer not to need the mailbox ticker to manage the | 328 | info->desc->ops->mark_txdone(cinfo, ret); |
| 489 | * transfer queueing since the protocol layer queues things by itself. | ||
| 490 | * Unfortunately, we have to kick the mailbox framework after we have | ||
| 491 | * received our message. | ||
| 492 | */ | ||
| 493 | mbox_client_txdone(cinfo->chan, ret); | ||
| 494 | 329 | ||
| 495 | trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, | 330 | trace_scmi_xfer_end(xfer->transfer_id, xfer->hdr.id, |
| 496 | xfer->hdr.protocol_id, xfer->hdr.seq, | 331 | xfer->hdr.protocol_id, xfer->hdr.seq, |
| @@ -731,23 +566,12 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) · 234 unmodified lines | |||
| 731 | return 0; | 566 | return 0; |
| 732 | } | 567 | } |
| 733 | 568 | ||
| 734 | static int scmi_mailbox_check(struct device_node *np, int idx) | 569 | static int scmi_chan_setup(struct scmi_info *info, struct device *dev, |
| 735 | { | 570 | int prot_id, bool tx) |
| 736 | return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", | ||
| 737 | idx, NULL); | ||
| 738 | } | ||
| 739 | |||
| 740 | static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, | ||
| 741 | int prot_id, bool tx) | ||
| 742 | { | 571 | { |
| 743 | int ret, idx; | 572 | int ret, idx; |
| 744 | struct resource res; | ||
| 745 | resource_size_t size; | ||
| 746 | struct device_node *shmem, *np = dev->of_node; | ||
| 747 | struct scmi_chan_info *cinfo; | 573 | struct scmi_chan_info *cinfo; |
| 748 | struct mbox_client *cl; | ||
| 749 | struct idr *idr; | 574 | struct idr *idr; |
| 750 | const char *desc = tx ? "Tx" : "Rx"; | ||
| 751 | 575 | ||
| 752 | /* Transmit channel is first entry i.e. index 0 */ | 576 | /* Transmit channel is first entry i.e. index 0 */ |
| 753 | idx = tx ? 0 : 1; | 577 | idx = tx ? 0 : 1; |
| @@ -758,7 +582,7 @@ static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, · 4 unmodified lines | |||
| 758 | if (cinfo) | 582 | if (cinfo) |
| 759 | return 0; | 583 | return 0; |
| 760 | 584 | ||
| 761 | if (scmi_mailbox_check(np, idx)) { | 585 | if (!info->desc->ops->chan_available(dev, idx)) { |
| 762 | cinfo = idr_find(idr, SCMI_PROTOCOL_BASE); | 586 | cinfo = idr_find(idr, SCMI_PROTOCOL_BASE); |
| 763 | if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ | 587 | if (unlikely(!cinfo)) /* Possible only if platform has no Rx */ |
| 764 | return -EINVAL; | 588 | return -EINVAL; |
| @@ -771,36 +595,9 @@ static int scmi_mbox_chan_setup(struct scmi_info *info, struct device *dev, · 6 unmodified lines | |||
| 771 | 595 | ||
| 772 | cinfo->dev = dev; | 596 | cinfo->dev = dev; |
| 773 | 597 | ||
| 774 | cl = &cinfo->cl; | 598 | ret = info->desc->ops->chan_setup(cinfo, info->dev, tx); |
| 775 | cl->dev = dev; | 599 | if (ret) |
| 776 | cl->rx_callback = scmi_rx_callback; | ||
| 777 | cl->tx_prepare = tx ? scmi_tx_prepare : NULL; | ||
| 778 | cl->tx_block = false; | ||
| 779 | cl->knows_txdone = tx; | ||
| 780 | |||
| 781 | shmem = of_parse_phandle(np, "shmem", idx); | ||
| 782 | ret = of_address_to_resource(shmem, 0, &res); | ||
| 783 | of_node_put(shmem); | ||
| 784 | if (ret) { | ||
| 785 | dev_err(dev, "failed to get SCMI %s payload memory\n", desc); | ||
| 786 | return ret; | ||
| 787 | } | ||
| 788 | |||
| 789 | size = resource_size(&res); | ||
| 790 | cinfo->payload = devm_ioremap(info->dev, res.start, size); | ||
| 791 | if (!cinfo->payload) { | ||
| 792 | dev_err(dev, "failed to ioremap SCMI %s payload\n", desc); | ||
| 793 | return -EADDRNOTAVAIL; | ||
| 794 | } | ||
| 795 | |||
| 796 | cinfo->chan = mbox_request_channel(cl, idx); | ||
| 797 | if (IS_ERR(cinfo->chan)) { | ||
| 798 | ret = PTR_ERR(cinfo->chan); | ||
| 799 | if (ret != -EPROBE_DEFER) | ||
| 800 | dev_err(dev, "failed to request SCMI %s mailbox\n", | ||
| 801 | desc); | ||
| 802 | return ret; | 600 | return ret; |
| 803 | } | ||
| 804 | 601 | ||
| 805 | idr_alloc: | 602 | idr_alloc: |
| 806 | ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); | 603 | ret = idr_alloc(idr, cinfo, prot_id, prot_id + 1, GFP_KERNEL); |
| @@ -814,12 +611,12 @@ idr_alloc: · 7 unmodified lines | |||
| 814 | } | 611 | } |
| 815 | 612 | ||
| 816 | static inline int | 613 | static inline int |
| 817 | scmi_mbox_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) | 614 | scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) |
| 818 | { | 615 | { |
| 819 | int ret = scmi_mbox_chan_setup(info, dev, prot_id, true); | 616 | int ret = scmi_chan_setup(info, dev, prot_id, true); |
| 820 | 617 | ||
| 821 | if (!ret) /* Rx is optional, hence no error check */ | 618 | if (!ret) /* Rx is optional, hence no error check */ |
| 822 | scmi_mbox_chan_setup(info, dev, prot_id, false); | 619 | scmi_chan_setup(info, dev, prot_id, false); |
| 823 | 620 | ||
| 824 | return ret; | 621 | return ret; |
| 825 | } | 622 | } |
| @@ -837,7 +634,7 @@ scmi_create_protocol_device(struct device_node *np, struct scmi_info *info, · 11 unmodified lines | |||
| 837 | return; | 634 | return; |
| 838 | } | 635 | } |
| 839 | 636 | ||
| 840 | if (scmi_mbox_txrx_setup(info, &sdev->dev, prot_id)) { | 637 | if (scmi_txrx_setup(info, &sdev->dev, prot_id)) { |
| 841 | dev_err(&sdev->dev, "failed to setup transport\n"); | 638 | dev_err(&sdev->dev, "failed to setup transport\n"); |
| 842 | scmi_device_destroy(sdev); | 639 | scmi_device_destroy(sdev); |
| 843 | return; | 640 | return; |
| @@ -890,12 +687,6 @@ static int scmi_probe(struct platform_device *pdev) · 46 unmodified lines | |||
| 890 | struct device *dev = &pdev->dev; | 687 | struct device *dev = &pdev->dev; |
| 891 | struct device_node *child, *np = dev->of_node; | 688 | struct device_node *child, *np = dev->of_node; |
| 892 | 689 | ||
| 893 | /* Only mailbox method supported, check for the presence of one */ | ||
| 894 | if (scmi_mailbox_check(np, 0)) { | ||
| 895 | dev_err(dev, "no mailbox found in %pOF\n", np); | ||
| 896 | return -EINVAL; | ||
| 897 | } | ||
| 898 | |||
| 899 | desc = of_device_get_match_data(dev); | 690 | desc = of_device_get_match_data(dev); |
| 900 | if (!desc) | 691 | if (!desc) |
| 901 | return -EINVAL; | 692 | return -EINVAL; |
| @@ -920,7 +711,7 @@ static int scmi_probe(struct platform_device *pdev) · 18 unmodified lines | |||
| 920 | handle->dev = info->dev; | 711 | handle->dev = info->dev; |
| 921 | handle->version = &info->version; | 712 | handle->version = &info->version; |
| 922 | 713 | ||
| 923 | ret = scmi_mbox_txrx_setup(info, dev, SCMI_PROTOCOL_BASE); | 714 | ret = scmi_txrx_setup(info, dev, SCMI_PROTOCOL_BASE); |
| 924 | if (ret) | 715 | if (ret) |
| 925 | return ret; | 716 | return ret; |
| 926 | 717 | ||
| @@ -955,19 +746,9 @@ static int scmi_probe(struct platform_device *pdev) · 28 unmodified lines | |||
| 955 | return 0; | 746 | return 0; |
| 956 | } | 747 | } |
| 957 | 748 | ||
| 958 | static int scmi_mbox_free_channel(int id, void *p, void *data) | 749 | void scmi_free_channel(struct scmi_chan_info *cinfo, struct idr *idr, int id) |
| 959 | { | 750 | { |
| 960 | struct scmi_chan_info *cinfo = p; | ||
| 961 | struct idr *idr = data; | ||
| 962 | |||
| 963 | if (!IS_ERR_OR_NULL(cinfo->chan)) { | ||
| 964 | mbox_free_channel(cinfo->chan); | ||
| 965 | cinfo->chan = NULL; | ||
| 966 | } | ||
| 967 | |||
| 968 | idr_remove(idr, id); | 751 | idr_remove(idr, id); |
| 969 | |||
| 970 | return 0; | ||
| 971 | } | 752 | } |
| 972 | 753 | ||
| 973 | static int scmi_remove(struct platform_device *pdev) | 754 | static int scmi_remove(struct platform_device *pdev) |
| @@ -987,11 +768,11 @@ static int scmi_remove(struct platform_device *pdev) · 13 unmodified lines | |||
| 987 | return ret; | 768 | return ret; |
| 988 | 769 | ||
| 989 | /* Safe to free channels since no more users */ | 770 | /* Safe to free channels since no more users */ |
| 990 | ret = idr_for_each(idr, scmi_mbox_free_channel, idr); | 771 | ret = idr_for_each(idr, info->desc->ops->chan_free, idr); |
| 991 | idr_destroy(&info->tx_idr); | 772 | idr_destroy(&info->tx_idr); |
| 992 | 773 | ||
| 993 | idr = &info->rx_idr; | 774 | idr = &info->rx_idr; |
| 994 | ret = idr_for_each(idr, scmi_mbox_free_channel, idr); | 775 | ret = idr_for_each(idr, info->desc->ops->chan_free, idr); |
| 995 | idr_destroy(&info->rx_idr); | 776 | idr_destroy(&info->rx_idr); |
| 996 | 777 | ||
| 997 | return ret; | 778 | return ret; |
| @@ -1043,15 +824,9 @@ static struct attribute *versions_attrs[] = { · 45 unmodified lines | |||
| 1043 | }; | 824 | }; |
| 1044 | ATTRIBUTE_GROUPS(versions); | 825 | ATTRIBUTE_GROUPS(versions); |
| 1045 | 826 | ||
| 1046 | static const struct scmi_desc scmi_generic_desc = { | ||
| 1047 | .max_rx_timeout_ms = 30, /* We may increase this if required */ | ||
| 1048 | .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ | ||
| 1049 | .max_msg_size = 128, | ||
| 1050 | }; | ||
| 1051 | |||
| 1052 | /* Each compatible listed below must have descriptor associated with it */ | 827 | /* Each compatible listed below must have descriptor associated with it */ |
| 1053 | static const struct of_device_id scmi_of_match[] = { | 828 | static const struct of_device_id scmi_of_match[] = { |
| 1054 | { .compatible = "arm,scmi", .data = &scmi_generic_desc }, | 829 | { .compatible = "arm,scmi", .data = &scmi_mailbox_desc }, |
| 1055 | { /* Sentinel */ }, | 830 | { /* Sentinel */ }, |
| 1056 | }; | 831 | }; |
| 1057 | 832 | ||
| @@ -0,0 +1,184 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * System Control and Management Interface (SCMI) Message Mailbox Transport | ||
| 4 | * driver. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2019 ARM Ltd. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/err.h> | ||
| 10 | #include <linux/device.h> | ||
| 11 | #include <linux/mailbox_client.h> | ||
| 12 | #include <linux/of.h> | ||
| 13 | #include <linux/of_address.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | |||
| 16 | #include "common.h" | ||
| 17 | |||
| 18 | /** | ||
| 19 | * struct scmi_mailbox - Structure representing a SCMI mailbox transport | ||
| 20 | * | ||
| 21 | * @cl: Mailbox Client | ||
| 22 | * @chan: Transmit/Receive mailbox channel | ||
| 23 | * @cinfo: SCMI channel info | ||
| 24 | * @shmem: Transmit/Receive shared memory area | ||
| 25 | */ | ||
| 26 | struct scmi_mailbox { | ||
| 27 | struct mbox_client cl; | ||
| 28 | struct mbox_chan *chan; | ||
| 29 | struct scmi_chan_info *cinfo; | ||
| 30 | struct scmi_shared_mem __iomem *shmem; | ||
| 31 | }; | ||
| 32 | |||
| 33 | #define client_to_scmi_mailbox(c) container_of(c, struct scmi_mailbox, cl) | ||
| 34 | |||
| 35 | static void tx_prepare(struct mbox_client *cl, void *m) | ||
| 36 | { | ||
| 37 | struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); | ||
| 38 | |||
| 39 | shmem_tx_prepare(smbox->shmem, m); | ||
| 40 | } | ||
| 41 | |||
| 42 | static void rx_callback(struct mbox_client *cl, void *m) | ||
| 43 | { | ||
| 44 | struct scmi_mailbox *smbox = client_to_scmi_mailbox(cl); | ||
| 45 | |||
| 46 | scmi_rx_callback(smbox->cinfo, shmem_read_header(smbox->shmem)); | ||
| 47 | } | ||
| 48 | |||
| 49 | static bool mailbox_chan_available(struct device *dev, int idx) | ||
| 50 | { | ||
| 51 | return !of_parse_phandle_with_args(dev->of_node, "mboxes", | ||
| 52 | "#mbox-cells", idx, NULL); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int mailbox_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, | ||
| 56 | bool tx) | ||
| 57 | { | ||
| 58 | const char *desc = tx ? "Tx" : "Rx"; | ||
| 59 | struct device *cdev = cinfo->dev; | ||
| 60 | struct scmi_mailbox *smbox; | ||
| 61 | struct device_node *shmem; | ||
| 62 | int ret, idx = tx ? 0 : 1; | ||
| 63 | struct mbox_client *cl; | ||
| 64 | resource_size_t size; | ||
| 65 | struct resource res; | ||
| 66 | |||
| 67 | smbox = devm_kzalloc(dev, sizeof(*smbox), GFP_KERNEL); | ||
| 68 | if (!smbox) | ||
| 69 | return -ENOMEM; | ||
| 70 | |||
| 71 | shmem = of_parse_phandle(cdev->of_node, "shmem", idx); | ||
| 72 | ret = of_address_to_resource(shmem, 0, &res); | ||
| 73 | of_node_put(shmem); | ||
| 74 | if (ret) { | ||
| 75 | dev_err(cdev, "failed to get SCMI %s shared memory\n", desc); | ||
| 76 | return ret; | ||
| 77 | } | ||
| 78 | |||
| 79 | size = resource_size(&res); | ||
| 80 | smbox->shmem = devm_ioremap(dev, res.start, size); | ||
| 81 | if (!smbox->shmem) { | ||
| 82 | dev_err(dev, "failed to ioremap SCMI %s shared memory\n", desc); | ||
| 83 | return -EADDRNOTAVAIL; | ||
| 84 | } | ||
| 85 | |||
| 86 | cl = &smbox->cl; | ||
| 87 | cl->dev = cdev; | ||
| 88 | cl->tx_prepare = tx ? tx_prepare : NULL; | ||
| 89 | cl->rx_callback = rx_callback; | ||
| 90 | cl->tx_block = false; | ||
| 91 | cl->knows_txdone = tx; | ||
| 92 | |||
| 93 | smbox->chan = mbox_request_channel(cl, tx ? 0 : 1); | ||
| 94 | if (IS_ERR(smbox->chan)) { | ||
| 95 | ret = PTR_ERR(smbox->chan); | ||
| 96 | if (ret != -EPROBE_DEFER) | ||
| 97 | dev_err(cdev, "failed to request SCMI %s mailbox\n", | ||
| 98 | tx ? "Tx" : "Rx"); | ||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | |||
| 102 | cinfo->transport_info = smbox; | ||
| 103 | smbox->cinfo = cinfo; | ||
| 104 | |||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | static int mailbox_chan_free(int id, void *p, void *data) | ||
| 109 | { | ||
| 110 | struct scmi_chan_info *cinfo = p; | ||
| 111 | struct scmi_mailbox *smbox = cinfo->transport_info; | ||
| 112 | |||
| 113 | if (!IS_ERR(smbox->chan)) { | ||
| 114 | mbox_free_channel(smbox->chan); | ||
| 115 | cinfo->transport_info = NULL; | ||
| 116 | smbox->chan = NULL; | ||
| 117 | smbox->cinfo = NULL; | ||
| 118 | } | ||
| 119 | |||
| 120 | scmi_free_channel(cinfo, data, id); | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int mailbox_send_message(struct scmi_chan_info *cinfo, | ||
| 126 | struct scmi_xfer *xfer) | ||
| 127 | { | ||
| 128 | struct scmi_mailbox *smbox = cinfo->transport_info; | ||
| 129 | int ret; | ||
| 130 | |||
| 131 | ret = mbox_send_message(smbox->chan, xfer); | ||
| 132 | |||
| 133 | /* mbox_send_message returns non-negative value on success, so reset */ | ||
| 134 | if (ret > 0) | ||
| 135 | ret = 0; | ||
| 136 | |||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | |||
| 140 | static void mailbox_mark_txdone(struct scmi_chan_info *cinfo, int ret) | ||
| 141 | { | ||
| 142 | struct scmi_mailbox *smbox = cinfo->transport_info; | ||
| 143 | |||
| 144 | /* | ||
| 145 | * NOTE: we might prefer not to need the mailbox ticker to manage the | ||
| 146 | * transfer queueing since the protocol layer queues things by itself. | ||
| 147 | * Unfortunately, we have to kick the mailbox framework after we have | ||
| 148 | * received our message. | ||
| 149 | */ | ||
| 150 | mbox_client_txdone(smbox->chan, ret); | ||
| 151 | } | ||
| 152 | |||
| 153 | static void mailbox_fetch_response(struct scmi_chan_info *cinfo, | ||
| 154 | struct scmi_xfer *xfer) | ||
| 155 | { | ||
| 156 | struct scmi_mailbox *smbox = cinfo->transport_info; | ||
| 157 | |||
| 158 | shmem_fetch_response(smbox->shmem, xfer); | ||
| 159 | } | ||
| 160 | |||
| 161 | static bool | ||
| 162 | mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) | ||
| 163 | { | ||
| 164 | struct scmi_mailbox *smbox = cinfo->transport_info; | ||
| 165 | |||
| 166 | return shmem_poll_done(smbox->shmem, xfer); | ||
| 167 | } | ||
| 168 | |||
| 169 | static struct scmi_transport_ops scmi_mailbox_ops = { | ||
| 170 | .chan_available = mailbox_chan_available, | ||
| 171 | .chan_setup = mailbox_chan_setup, | ||
| 172 | .chan_free = mailbox_chan_free, | ||
| 173 | .send_message = mailbox_send_message, | ||
| 174 | .mark_txdone = mailbox_mark_txdone, | ||
| 175 | .fetch_response = mailbox_fetch_response, | ||
| 176 | .poll_done = mailbox_poll_done, | ||
| 177 | }; | ||
| 178 | |||
| 179 | const struct scmi_desc scmi_mailbox_desc = { | ||
| 180 | .ops = &scmi_mailbox_ops, | ||
| 181 | .max_rx_timeout_ms = 30, /* We may increase this if required */ | ||
| 182 | .max_msg = 20, /* Limited by MBOX_TX_QUEUE_LEN */ | ||
| 183 | .max_msg_size = 128, | ||
| 184 | }; | ||
| @@ -89,7 +89,7 @@ struct scmi_msg_resp_perf_describe_levels { · 88 unmodified lines | |||
| 89 | __le32 power; | 89 | __le32 power; |
| 90 | __le16 transition_latency_us; | 90 | __le16 transition_latency_us; |
| 91 | __le16 reserved; | 91 | __le16 reserved; |
| 92 | } opp[0]; | 92 | } opp[]; |
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | struct scmi_perf_get_fc_info { | 95 | struct scmi_perf_get_fc_info { |
| @@ -0,0 +1,83 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * For transport using shared mem structure. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 ARM Ltd. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/io.h> | ||
| 9 | #include <linux/processor.h> | ||
| 10 | #include <linux/types.h> | ||
| 11 | |||
| 12 | #include "common.h" | ||
| 13 | |||
| 14 | /* | ||
| 15 | * SCMI specification requires all parameters, message headers, return | ||
| 16 | * arguments or any protocol data to be expressed in little endian | ||
| 17 | * format only. | ||
| 18 | */ | ||
| 19 | struct scmi_shared_mem { | ||
| 20 | __le32 reserved; | ||
| 21 | __le32 channel_status; | ||
| 22 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR BIT(1) | ||
| 23 | #define SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE BIT(0) | ||
| 24 | __le32 reserved1[2]; | ||
| 25 | __le32 flags; | ||
| 26 | #define SCMI_SHMEM_FLAG_INTR_ENABLED BIT(0) | ||
| 27 | __le32 length; | ||
| 28 | __le32 msg_header; | ||
| 29 | u8 msg_payload[]; | ||
| 30 | }; | ||
| 31 | |||
| 32 | void shmem_tx_prepare(struct scmi_shared_mem __iomem *shmem, | ||
| 33 | struct scmi_xfer *xfer) | ||
| 34 | { | ||
| 35 | /* | ||
| 36 | * Ideally channel must be free by now unless OS timeout last | ||
| 37 | * request and platform continued to process the same, wait | ||
| 38 | * until it releases the shared memory, otherwise we may endup | ||
| 39 | * overwriting its response with new message payload or vice-versa | ||
| 40 | */ | ||
| 41 | spin_until_cond(ioread32(&shmem->channel_status) & | ||
| 42 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); | ||
| 43 | /* Mark channel busy + clear error */ | ||
| 44 | iowrite32(0x0, &shmem->channel_status); | ||
| 45 | iowrite32(xfer->hdr.poll_completion ? 0 : SCMI_SHMEM_FLAG_INTR_ENABLED, | ||
| 46 | &shmem->flags); | ||
| 47 | iowrite32(sizeof(shmem->msg_header) + xfer->tx.len, &shmem->length); | ||
| 48 | iowrite32(pack_scmi_header(&xfer->hdr), &shmem->msg_header); | ||
| 49 | if (xfer->tx.buf) | ||
| 50 | memcpy_toio(shmem->msg_payload, xfer->tx.buf, xfer->tx.len); | ||
| 51 | } | ||
| 52 | |||
| 53 | u32 shmem_read_header(struct scmi_shared_mem __iomem *shmem) | ||
| 54 | { | ||
| 55 | return ioread32(&shmem->msg_header); | ||
| 56 | } | ||
| 57 | |||
| 58 | void shmem_fetch_response(struct scmi_shared_mem __iomem *shmem, | ||
| 59 | struct scmi_xfer *xfer) | ||
| 60 | { | ||
| 61 | xfer->hdr.status = ioread32(shmem->msg_payload); | ||
| 62 | /* Skip the length of header and status in shmem area i.e 8 bytes */ | ||
| 63 | xfer->rx.len = min_t(size_t, xfer->rx.len, | ||
| 64 | ioread32(&shmem->length) - 8); | ||
| 65 | |||
| 66 | /* Take a copy to the rx buffer.. */ | ||
| 67 | memcpy_fromio(xfer->rx.buf, shmem->msg_payload + 4, xfer->rx.len); | ||
| 68 | } | ||
| 69 | |||
| 70 | bool shmem_poll_done(struct scmi_shared_mem __iomem *shmem, | ||
| 71 | struct scmi_xfer *xfer) | ||
| 72 | { | ||
| 73 | u16 xfer_id; | ||
| 74 | |||
| 75 | xfer_id = MSG_XTRACT_TOKEN(ioread32(&shmem->msg_header)); | ||
| 76 | |||
| 77 | if (xfer->hdr.seq != xfer_id) | ||
| 78 | return false; | ||
| 79 | |||
| 80 | return ioread32(&shmem->channel_status) & | ||
| 81 | (SCMI_SHMEM_CHAN_STAT_CHANNEL_ERROR | | ||
| 82 | SCMI_SHMEM_CHAN_STAT_CHANNEL_FREE); | ||
| 83 | } | ||
| @@ -262,12 +262,12 @@ struct scpi_drvinfo { · 261 unmodified lines | |||
| 262 | struct scpi_shared_mem { | 262 | struct scpi_shared_mem { |
| 263 | __le32 command; | 263 | __le32 command; |
| 264 | __le32 status; | 264 | __le32 status; |
| 265 | u8 payload[0]; | 265 | u8 payload[]; |
| 266 | } __packed; | 266 | } __packed; |
| 267 | 267 | ||
| 268 | struct legacy_scpi_shared_mem { | 268 | struct legacy_scpi_shared_mem { |
| 269 | __le32 status; | 269 | __le32 status; |
| 270 | u8 payload[0]; | 270 | u8 payload[]; |
| 271 | } __packed; | 271 | } __packed; |
| 272 | 272 | ||
| 273 | struct scp_capabilities { | 273 | struct scp_capabilities { |
| @@ -93,7 +93,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { · 92 unmodified lines | |||
| 93 | { "kpp", IMX_SC_R_KPP, 1, false, 0 }, | 93 | { "kpp", IMX_SC_R_KPP, 1, false, 0 }, |
| 94 | { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, | 94 | { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, |
| 95 | { "mu_a", IMX_SC_R_MU_0A, 14, true, 0 }, | 95 | { "mu_a", IMX_SC_R_MU_0A, 14, true, 0 }, |
| 96 | { "mu_b", IMX_SC_R_MU_13B, 1, true, 13 }, | 96 | { "mu_b", IMX_SC_R_MU_5B, 9, true, 5 }, |
| 97 | 97 | ||
| 98 | /* CONN SS */ | 98 | /* CONN SS */ |
| 99 | { "usb", IMX_SC_R_USB_0, 2, true, 0 }, | 99 | { "usb", IMX_SC_R_USB_0, 2, true, 0 }, |
| @@ -109,6 +109,7 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { · 9 unmodified lines | |||
| 109 | { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, | 109 | { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, |
| 110 | { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, | 110 | { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, |
| 111 | { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, | 111 | { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, |
| 112 | { "audio-clk-1", IMX_SC_R_AUDIO_CLK_1, 1, false, 0 }, | ||
| 112 | { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, | 113 | { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, |
| 113 | { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, | 114 | { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, |
| 114 | { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, | 115 | { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, |
| @@ -116,7 +117,13 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { · 1 unmodified line | |||
| 116 | { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, | 117 | { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, |
| 117 | { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, | 118 | { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, |
| 118 | { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, | 119 | { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, |
| 120 | { "spdif1", IMX_SC_R_SPDIF_1, 1, false, 0 }, | ||
| 119 | { "sai", IMX_SC_R_SAI_0, 3, true, 0 }, | 121 | { "sai", IMX_SC_R_SAI_0, 3, true, 0 }, |
| 122 | { "sai3", IMX_SC_R_SAI_3, 1, false, 0 }, | ||
| 123 | { "sai4", IMX_SC_R_SAI_4, 1, false, 0 }, | ||
| 124 | { "sai5", IMX_SC_R_SAI_5, 1, false, 0 }, | ||
| 125 | { "sai6", IMX_SC_R_SAI_6, 1, false, 0 }, | ||
| 126 | { "sai7", IMX_SC_R_SAI_7, 1, false, 0 }, | ||
| 120 | { "amix", IMX_SC_R_AMIX, 1, false, 0 }, | 127 | { "amix", IMX_SC_R_AMIX, 1, false, 0 }, |
| 121 | { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, | 128 | { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, |
| 122 | { "dsp", IMX_SC_R_DSP, 1, false, 0 }, | 129 | { "dsp", IMX_SC_R_DSP, 1, false, 0 }, |
| @@ -158,6 +165,10 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { · 35 unmodified lines | |||
| 158 | /* DC SS */ | 165 | /* DC SS */ |
| 159 | { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, | 166 | { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, |
| 160 | { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, | 167 | { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, |
| 168 | |||
| 169 | /* CM40 SS */ | ||
| 170 | { "cm40_i2c", IMX_SC_R_M4_0_I2C, 1, 0 }, | ||
| 171 | { "cm40_intmux", IMX_SC_R_M4_0_INTMUX, 1, 0 }, | ||
| 161 | }; | 172 | }; |
| 162 | 173 | ||
| 163 | static const struct imx_sc_pd_soc imx8qxp_scu_pd = { | 174 | static const struct imx_sc_pd_soc imx8qxp_scu_pd = { |
| @@ -44,6 +44,8 @@ static const struct meson_sm_chip gxbb_chip = { · 43 unmodified lines | |||
| 44 | CMD(SM_EFUSE_WRITE, 0x82000031), | 44 | CMD(SM_EFUSE_WRITE, 0x82000031), |
| 45 | CMD(SM_EFUSE_USER_MAX, 0x82000033), | 45 | CMD(SM_EFUSE_USER_MAX, 0x82000033), |
| 46 | CMD(SM_GET_CHIP_ID, 0x82000044), | 46 | CMD(SM_GET_CHIP_ID, 0x82000044), |
| 47 | CMD(SM_A1_PWRC_SET, 0x82000093), | ||
| 48 | CMD(SM_A1_PWRC_GET, 0x82000095), | ||
| 47 | { /* sentinel */ }, | 49 | { /* sentinel */ }, |
| 48 | }, | 50 | }, |
| 49 | }; | 51 | }; |
| @@ -7,7 +7,7 @@ config TEGRA_IVC · 6 unmodified lines | |||
| 7 | help | 7 | help |
| 8 | IVC (Inter-VM Communication) protocol is part of the IPC | 8 | IVC (Inter-VM Communication) protocol is part of the IPC |
| 9 | (Inter Processor Communication) framework on Tegra. It maintains the | 9 | (Inter Processor Communication) framework on Tegra. It maintains the |
| 10 | data and the different commuication channels in SysRAM or RAM and | 10 | data and the different communication channels in SysRAM or RAM and |
| 11 | keeps the content is synchronization between host CPU and remote | 11 | keeps the content is synchronization between host CPU and remote |
| 12 | processors. | 12 | processors. |
| 13 | 13 | ||
| @@ -1348,9 +1348,15 @@ static int dss_component_compare(struct device *dev, void *data) · 1347 unmodified lines | |||
| 1348 | return dev == child; | 1348 | return dev == child; |
| 1349 | } | 1349 | } |
| 1350 | 1350 | ||
| 1351 | struct dss_component_match_data { | ||
| 1352 | struct device *dev; | ||
| 1353 | struct component_match **match; | ||
| 1354 | }; | ||
| 1355 | |||
| 1351 | static int dss_add_child_component(struct device *dev, void *data) | 1356 | static int dss_add_child_component(struct device *dev, void *data) |
| 1352 | { | 1357 | { |
| 1353 | struct component_match **match = data; | 1358 | struct dss_component_match_data *cmatch = data; |
| 1359 | struct component_match **match = cmatch->match; | ||
| 1354 | 1360 | ||
| 1355 | /* | 1361 | /* |
| 1356 | * HACK | 1362 | * HACK |
| @@ -1361,7 +1367,17 @@ static int dss_add_child_component(struct device *dev, void *data) · 4 unmodified lines | |||
| 1361 | if (strstr(dev_name(dev), "rfbi")) | 1367 | if (strstr(dev_name(dev), "rfbi")) |
| 1362 | return 0; | 1368 | return 0; |
| 1363 | 1369 | ||
| 1364 | component_match_add(dev->parent, match, dss_component_compare, dev); | 1370 | /* |
| 1371 | * Handle possible interconnect target modules defined within the DSS. | ||
| 1372 | * The DSS components can be children of an interconnect target module | ||
| 1373 | * after the device tree has been updated for the module data. | ||
| 1374 | * See also omapdss_boot_init() for compatible fixup. | ||
| 1375 | */ | ||
| 1376 | if (strstr(dev_name(dev), "target-module")) | ||
| 1377 | return device_for_each_child(dev, cmatch, | ||
| 1378 | dss_add_child_component); | ||
| 1379 | |||
| 1380 | component_match_add(cmatch->dev, match, dss_component_compare, dev); | ||
| 1365 | 1381 | ||
| 1366 | return 0; | 1382 | return 0; |
| 1367 | } | 1383 | } |
| @@ -1404,6 +1420,7 @@ static int dss_probe_hardware(struct dss_device *dss) · 36 unmodified lines | |||
| 1404 | static int dss_probe(struct platform_device *pdev) | 1420 | static int dss_probe(struct platform_device *pdev) |
| 1405 | { | 1421 | { |
| 1406 | const struct soc_device_attribute *soc; | 1422 | const struct soc_device_attribute *soc; |
| 1423 | struct dss_component_match_data cmatch; | ||
| 1407 | struct component_match *match = NULL; | 1424 | struct component_match *match = NULL; |
| 1408 | struct resource *dss_mem; | 1425 | struct resource *dss_mem; |
| 1409 | struct dss_device *dss; | 1426 | struct dss_device *dss; |
| @@ -1481,7 +1498,9 @@ static int dss_probe(struct platform_device *pdev) · 71 unmodified lines | |||
| 1481 | 1498 | ||
| 1482 | omapdss_gather_components(&pdev->dev); | 1499 | omapdss_gather_components(&pdev->dev); |
| 1483 | 1500 | ||
| 1484 | device_for_each_child(&pdev->dev, &match, dss_add_child_component); | 1501 | cmatch.dev = &pdev->dev; |
| 1502 | cmatch.match = &match; | ||
| 1503 | device_for_each_child(&pdev->dev, &cmatch, dss_add_child_component); | ||
| 1485 | 1504 | ||
| 1486 | r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); | 1505 | r = component_master_add_with_match(&pdev->dev, &dss_component_ops, match); |
| 1487 | if (r) | 1506 | if (r) |
| @@ -178,9 +178,24 @@ static const struct of_device_id omapdss_of_fixups_whitelist[] __initconst = { · 177 unmodified lines | |||
| 178 | {}, | 178 | {}, |
| 179 | }; | 179 | }; |
| 180 | 180 | ||
| 181 | static void __init omapdss_find_children(struct device_node *np) | ||
| 182 | { | ||
| 183 | struct device_node *child; | ||
| 184 | |||
| 185 | for_each_available_child_of_node(np, child) { | ||
| 186 | if (!of_find_property(child, "compatible", NULL)) | ||
| 187 | continue; | ||
| 188 | |||
| 189 | omapdss_walk_device(child, true); | ||
| 190 | |||
| 191 | if (of_device_is_compatible(child, "ti,sysc")) | ||
| 192 | omapdss_find_children(child); | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 181 | static int __init omapdss_boot_init(void) | 196 | static int __init omapdss_boot_init(void) |
| 182 | { | 197 | { |
| 183 | struct device_node *dss, *child; | 198 | struct device_node *dss; |
| 184 | 199 | ||
| 185 | INIT_LIST_HEAD(&dss_conv_list); | 200 | INIT_LIST_HEAD(&dss_conv_list); |
| 186 | 201 | ||
| @@ -190,13 +205,7 @@ static int __init omapdss_boot_init(void) · 3 unmodified lines | |||
| 190 | goto put_node; | 205 | goto put_node; |
| 191 | 206 | ||
| 192 | omapdss_walk_device(dss, true); | 207 | omapdss_walk_device(dss, true); |
| 193 | 208 | omapdss_find_children(dss); | |
| 194 | for_each_available_child_of_node(dss, child) { | ||
| 195 | if (!of_find_property(child, "compatible", NULL)) | ||
| 196 | continue; | ||
| 197 | |||
| 198 | omapdss_walk_device(child, true); | ||
| 199 | } | ||
| 200 | 209 | ||
| 201 | while (!list_empty(&dss_conv_list)) { | 210 | while (!list_empty(&dss_conv_list)) { |
| 202 | struct dss_conv_node *n; | 211 | struct dss_conv_node *n; |
| @@ -1158,6 +1158,11 @@ static void emc_debugfs_init(struct device *dev, struct tegra_emc *emc) · 1157 unmodified lines | |||
| 1158 | emc->debugfs.max_rate = emc->timings[i].rate; | 1158 | emc->debugfs.max_rate = emc->timings[i].rate; |
| 1159 | } | 1159 | } |
| 1160 | 1160 | ||
| 1161 | if (!emc->num_timings) { | ||
| 1162 | emc->debugfs.min_rate = clk_get_rate(emc->clk); | ||
| 1163 | emc->debugfs.max_rate = emc->debugfs.min_rate; | ||
| 1164 | } | ||
| 1165 | |||
| 1161 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, | 1166 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, |
| 1162 | emc->debugfs.max_rate); | 1167 | emc->debugfs.max_rate); |
| 1163 | if (err < 0) { | 1168 | if (err < 0) { |
| @@ -628,6 +628,11 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) · 627 unmodified lines | |||
| 628 | emc->debugfs.max_rate = emc->timings[i].rate; | 628 | emc->debugfs.max_rate = emc->timings[i].rate; |
| 629 | } | 629 | } |
| 630 | 630 | ||
| 631 | if (!emc->num_timings) { | ||
| 632 | emc->debugfs.min_rate = clk_get_rate(emc->clk); | ||
| 633 | emc->debugfs.max_rate = emc->debugfs.min_rate; | ||
| 634 | } | ||
| 635 | |||
| 631 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, | 636 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, |
| 632 | emc->debugfs.max_rate); | 637 | emc->debugfs.max_rate); |
| 633 | if (err < 0) { | 638 | if (err < 0) { |
| @@ -1256,6 +1256,11 @@ static void tegra_emc_debugfs_init(struct tegra_emc *emc) · 1255 unmodified lines | |||
| 1256 | emc->debugfs.max_rate = emc->timings[i].rate; | 1256 | emc->debugfs.max_rate = emc->timings[i].rate; |
| 1257 | } | 1257 | } |
| 1258 | 1258 | ||
| 1259 | if (!emc->num_timings) { | ||
| 1260 | emc->debugfs.min_rate = clk_get_rate(emc->clk); | ||
| 1261 | emc->debugfs.max_rate = emc->debugfs.min_rate; | ||
| 1262 | } | ||
| 1263 | |||
| 1259 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, | 1264 | err = clk_set_rate_range(emc->clk, emc->debugfs.min_rate, |
| 1260 | emc->debugfs.max_rate); | 1265 | emc->debugfs.max_rate); |
| 1261 | if (err < 0) { | 1266 | if (err < 0) { |
| @@ -11,7 +11,7 @@ obj-$(CONFIG_ARCH_DOVE) += dove/ · 10 unmodified lines | |||
| 11 | obj-$(CONFIG_MACH_DOVE) += dove/ | 11 | obj-$(CONFIG_MACH_DOVE) += dove/ |
| 12 | obj-y += fsl/ | 12 | obj-y += fsl/ |
| 13 | obj-$(CONFIG_ARCH_GEMINI) += gemini/ | 13 | obj-$(CONFIG_ARCH_GEMINI) += gemini/ |
| 14 | obj-$(CONFIG_ARCH_MXC) += imx/ | 14 | obj-y += imx/ |
| 15 | obj-$(CONFIG_ARCH_IXP4XX) += ixp4xx/ | 15 | obj-$(CONFIG_ARCH_IXP4XX) += ixp4xx/ |
| 16 | obj-$(CONFIG_SOC_XWAY) += lantiq/ | 16 | obj-$(CONFIG_SOC_XWAY) += lantiq/ |
| 17 | obj-y += mediatek/ | 17 | obj-y += mediatek/ |
| @@ -48,6 +48,19 @@ config MESON_EE_PM_DOMAINS · 47 unmodified lines | |||
| 48 | Say yes to expose Amlogic Meson Everything-Else Power Domains as | 48 | Say yes to expose Amlogic Meson Everything-Else Power Domains as |
| 49 | Generic Power Domains. | 49 | Generic Power Domains. |
| 50 | 50 | ||
| 51 | config MESON_SECURE_PM_DOMAINS | ||
| 52 | bool "Amlogic Meson Secure Power Domains driver" | ||
| 53 | depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM | ||
| 54 | depends on PM && OF | ||
| 55 | depends on HAVE_ARM_SMCCC | ||
| 56 | default ARCH_MESON | ||
| 57 | select PM_GENERIC_DOMAINS | ||
| 58 | select PM_GENERIC_DOMAINS_OF | ||
| 59 | help | ||
| 60 | Support for the power controller on Amlogic A1/C1 series. | ||
| 61 | Say yes to expose Amlogic Meson Secure Power Domains as Generic | ||
| 62 | Power Domains. | ||
| 63 | |||
| 51 | config MESON_MX_SOCINFO | 64 | config MESON_MX_SOCINFO |
| 52 | bool "Amlogic Meson MX SoC Information driver" | 65 | bool "Amlogic Meson MX SoC Information driver" |
| 53 | depends on ARCH_MESON || COMPILE_TEST | 66 | depends on ARCH_MESON || COMPILE_TEST |
| @@ -5,3 +5,4 @@ obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o · 4 unmodified lines | |||
| 5 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o | 5 | obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o |
| 6 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o | 6 | obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o |
| 7 | obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o | 7 | obj-$(CONFIG_MESON_EE_PM_DOMAINS) += meson-ee-pwrc.o |
| 8 | obj-$(CONFIG_MESON_SECURE_PM_DOMAINS) += meson-secure-pwrc.o | ||
| @@ -0,0 +1,204 @@ | |||
| 1 | // SPDX-License-Identifier: (GPL-2.0+ OR MIT) | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2019 Amlogic, Inc. | ||
| 4 | * Author: Jianxin Pan <jianxin.pan@amlogic.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 8 | |||
| 9 | #include <linux/io.h> | ||
| 10 | #include <linux/of_device.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/pm_domain.h> | ||
| 13 | #include <dt-bindings/power/meson-a1-power.h> | ||
| 14 | #include <linux/arm-smccc.h> | ||
| 15 | #include <linux/firmware/meson/meson_sm.h> | ||
| 16 | |||
| 17 | #define PWRC_ON 1 | ||
| 18 | #define PWRC_OFF 0 | ||
| 19 | |||
| 20 | struct meson_secure_pwrc_domain { | ||
| 21 | struct generic_pm_domain base; | ||
| 22 | unsigned int index; | ||
| 23 | struct meson_secure_pwrc *pwrc; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct meson_secure_pwrc { | ||
| 27 | struct meson_secure_pwrc_domain *domains; | ||
| 28 | struct genpd_onecell_data xlate; | ||
| 29 | struct meson_sm_firmware *fw; | ||
| 30 | }; | ||
| 31 | |||
| 32 | struct meson_secure_pwrc_domain_desc { | ||
| 33 | unsigned int index; | ||
| 34 | unsigned int flags; | ||
| 35 | char *name; | ||
| 36 | bool (*is_off)(struct meson_secure_pwrc_domain *pwrc_domain); | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct meson_secure_pwrc_domain_data { | ||
| 40 | unsigned int count; | ||
| 41 | struct meson_secure_pwrc_domain_desc *domains; | ||
| 42 | }; | ||
| 43 | |||
| 44 | static bool pwrc_secure_is_off(struct meson_secure_pwrc_domain *pwrc_domain) | ||
| 45 | { | ||
| 46 | int is_off = 1; | ||
| 47 | |||
| 48 | if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_GET, &is_off, | ||
| 49 | pwrc_domain->index, 0, 0, 0, 0) < 0) | ||
| 50 | pr_err("failed to get power domain status\n"); | ||
| 51 | |||
| 52 | return is_off; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int meson_secure_pwrc_off(struct generic_pm_domain *domain) | ||
| 56 | { | ||
| 57 | int ret = 0; | ||
| 58 | struct meson_secure_pwrc_domain *pwrc_domain = | ||
| 59 | container_of(domain, struct meson_secure_pwrc_domain, base); | ||
| 60 | |||
| 61 | if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL, | ||
| 62 | pwrc_domain->index, PWRC_OFF, 0, 0, 0) < 0) { | ||
| 63 | pr_err("failed to set power domain off\n"); | ||
| 64 | ret = -EINVAL; | ||
| 65 | } | ||
| 66 | |||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | |||
| 70 | static int meson_secure_pwrc_on(struct generic_pm_domain *domain) | ||
| 71 | { | ||
| 72 | int ret = 0; | ||
| 73 | struct meson_secure_pwrc_domain *pwrc_domain = | ||
| 74 | container_of(domain, struct meson_secure_pwrc_domain, base); | ||
| 75 | |||
| 76 | if (meson_sm_call(pwrc_domain->pwrc->fw, SM_A1_PWRC_SET, NULL, | ||
| 77 | pwrc_domain->index, PWRC_ON, 0, 0, 0) < 0) { | ||
| 78 | pr_err("failed to set power domain on\n"); | ||
| 79 | ret = -EINVAL; | ||
| 80 | } | ||
| 81 | |||
| 82 | return ret; | ||
| 83 | } | ||
| 84 | |||
| 85 | #define SEC_PD(__name, __flag) \ | ||
| 86 | [PWRC_##__name##_ID] = \ | ||
| 87 | { \ | ||
| 88 | .name = #__name, \ | ||
| 89 | .index = PWRC_##__name##_ID, \ | ||
| 90 | .is_off = pwrc_secure_is_off, \ | ||
| 91 | .flags = __flag, \ | ||
| 92 | } | ||
| 93 | |||
| 94 | static struct meson_secure_pwrc_domain_desc a1_pwrc_domains[] = { | ||
| 95 | SEC_PD(DSPA, 0), | ||
| 96 | SEC_PD(DSPB, 0), | ||
| 97 | /* UART should keep working in ATF after suspend and before resume */ | ||
| 98 | SEC_PD(UART, GENPD_FLAG_ALWAYS_ON), | ||
| 99 | /* DMC is for DDR PHY ana/dig and DMC, and should be always on */ | ||
| 100 | SEC_PD(DMC, GENPD_FLAG_ALWAYS_ON), | ||
| 101 | SEC_PD(I2C, 0), | ||
| 102 | SEC_PD(PSRAM, 0), | ||
| 103 | SEC_PD(ACODEC, 0), | ||
| 104 | SEC_PD(AUDIO, 0), | ||
| 105 | SEC_PD(OTP, 0), | ||
| 106 | SEC_PD(DMA, 0), | ||
| 107 | SEC_PD(SD_EMMC, 0), | ||
| 108 | SEC_PD(RAMA, 0), | ||
| 109 | /* SRAMB is used as ATF runtime memory, and should be always on */ | ||
| 110 | SEC_PD(RAMB, GENPD_FLAG_ALWAYS_ON), | ||
| 111 | SEC_PD(IR, 0), | ||
| 112 | SEC_PD(SPICC, 0), | ||
| 113 | SEC_PD(SPIFC, 0), | ||
| 114 | SEC_PD(USB, 0), | ||
| 115 | /* NIC is for the Arm NIC-400 interconnect, and should be always on */ | ||
| 116 | SEC_PD(NIC, GENPD_FLAG_ALWAYS_ON), | ||
| 117 | SEC_PD(PDMIN, 0), | ||
| 118 | SEC_PD(RSA, 0), | ||
| 119 | }; | ||
| 120 | |||
| 121 | static int meson_secure_pwrc_probe(struct platform_device *pdev) | ||
| 122 | { | ||
| 123 | int i; | ||
| 124 | struct device_node *sm_np; | ||
| 125 | struct meson_secure_pwrc *pwrc; | ||
| 126 | const struct meson_secure_pwrc_domain_data *match; | ||
| 127 | |||
| 128 | match = of_device_get_match_data(&pdev->dev); | ||
| 129 | if (!match) { | ||
| 130 | dev_err(&pdev->dev, "failed to get match data\n"); | ||
| 131 | return -ENODEV; | ||
| 132 | } | ||
| 133 | |||
| 134 | sm_np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gxbb-sm"); | ||
| 135 | if (!sm_np) { | ||
| 136 | dev_err(&pdev->dev, "no secure-monitor node\n"); | ||
| 137 | return -ENODEV; | ||
| 138 | } | ||
| 139 | |||
| 140 | pwrc = devm_kzalloc(&pdev->dev, sizeof(*pwrc), GFP_KERNEL); | ||
| 141 | if (!pwrc) | ||
| 142 | return -ENOMEM; | ||
| 143 | |||
| 144 | pwrc->fw = meson_sm_get(sm_np); | ||
| 145 | of_node_put(sm_np); | ||
| 146 | if (!pwrc->fw) | ||
| 147 | return -EPROBE_DEFER; | ||
| 148 | |||
| 149 | pwrc->xlate.domains = devm_kcalloc(&pdev->dev, match->count, | ||
| 150 | sizeof(*pwrc->xlate.domains), | ||
| 151 | GFP_KERNEL); | ||
| 152 | if (!pwrc->xlate.domains) | ||
| 153 | return -ENOMEM; | ||
| 154 | |||
| 155 | pwrc->domains = devm_kcalloc(&pdev->dev, match->count, | ||
| 156 | sizeof(*pwrc->domains), GFP_KERNEL); | ||
| 157 | if (!pwrc->domains) | ||
| 158 | return -ENOMEM; | ||
| 159 | |||
| 160 | pwrc->xlate.num_domains = match->count; | ||
| 161 | platform_set_drvdata(pdev, pwrc); | ||
| 162 | |||
| 163 | for (i = 0 ; i < match->count ; ++i) { | ||
| 164 | struct meson_secure_pwrc_domain *dom = &pwrc->domains[i]; | ||
| 165 | |||
| 166 | if (!match->domains[i].index) | ||
| 167 | continue; | ||
| 168 | |||
| 169 | dom->pwrc = pwrc; | ||
| 170 | dom->index = match->domains[i].index; | ||
| 171 | dom->base.name = match->domains[i].name; | ||
| 172 | dom->base.flags = match->domains[i].flags; | ||
| 173 | dom->base.power_on = meson_secure_pwrc_on; | ||
| 174 | dom->base.power_off = meson_secure_pwrc_off; | ||
| 175 | |||
| 176 | pm_genpd_init(&dom->base, NULL, match->domains[i].is_off(dom)); | ||
| 177 | |||
| 178 | pwrc->xlate.domains[i] = &dom->base; | ||
| 179 | } | ||
| 180 | |||
| 181 | return of_genpd_add_provider_onecell(pdev->dev.of_node, &pwrc->xlate); | ||
| 182 | } | ||
| 183 | |||
| 184 | static struct meson_secure_pwrc_domain_data meson_secure_a1_pwrc_data = { | ||
| 185 | .domains = a1_pwrc_domains, | ||
| 186 | .count = ARRAY_SIZE(a1_pwrc_domains), | ||
| 187 | }; | ||
| 188 | |||
| 189 | static const struct of_device_id meson_secure_pwrc_match_table[] = { | ||
| 190 | { | ||
| 191 | .compatible = "amlogic,meson-a1-pwrc", | ||
| 192 | .data = &meson_secure_a1_pwrc_data, | ||
| 193 | }, | ||
| 194 | { /* sentinel */ } | ||
| 195 | }; | ||
| 196 | |||
| 197 | static struct platform_driver meson_secure_pwrc_driver = { | ||
| 198 | .probe = meson_secure_pwrc_probe, | ||
| 199 | .driver = { | ||
| 200 | .name = "meson_secure_pwrc", | ||
| 201 | .of_match_table = meson_secure_pwrc_match_table, | ||
| 202 | }, | ||
| 203 | }; | ||
| 204 | builtin_platform_driver(meson_secure_pwrc_driver); | ||
| @@ -1,7 +1,7 @@ | |||
| 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
| 2 | /* | 2 | /* |
| 3 | * Copyright 2014-2016 Freescale Semiconductor Inc. | 3 | * Copyright 2014-2016 Freescale Semiconductor Inc. |
| 4 | * Copyright 2016 NXP | 4 | * Copyright 2016-2019 NXP |
| 5 | * | 5 | * |
| 6 | */ | 6 | */ |
| 7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| @@ -432,6 +432,69 @@ int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, · 424 unmodified lines | |||
| 432 | } | 432 | } |
| 433 | EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq); | 433 | EXPORT_SYMBOL(dpaa2_io_service_enqueue_fq); |
| 434 | 434 | ||
| 435 | /** | ||
| 436 | * dpaa2_io_service_enqueue_multiple_fq() - Enqueue multiple frames | ||
| 437 | * to a frame queue using one fqid. | ||
| 438 | * @d: the given DPIO service. | ||
| 439 | * @fqid: the given frame queue id. | ||
| 440 | * @fd: the frame descriptor which is enqueued. | ||
| 441 | * @nb: number of frames to be enqueud | ||
| 442 | * | ||
| 443 | * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready, | ||
| 444 | * or -ENODEV if there is no dpio service. | ||
| 445 | */ | ||
| 446 | int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d, | ||
| 447 | u32 fqid, | ||
| 448 | const struct dpaa2_fd *fd, | ||
| 449 | int nb) | ||
| 450 | { | ||
| 451 | struct qbman_eq_desc ed; | ||
| 452 | |||
| 453 | d = service_select(d); | ||
| 454 | if (!d) | ||
| 455 | return -ENODEV; | ||
| 456 | |||
| 457 | qbman_eq_desc_clear(&ed); | ||
| 458 | qbman_eq_desc_set_no_orp(&ed, 0); | ||
| 459 | qbman_eq_desc_set_fq(&ed, fqid); | ||
| 460 | |||
| 461 | return qbman_swp_enqueue_multiple(d->swp, &ed, fd, 0, nb); | ||
| 462 | } | ||
| 463 | EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_fq); | ||
| 464 | |||
| 465 | /** | ||
| 466 | * dpaa2_io_service_enqueue_multiple_desc_fq() - Enqueue multiple frames | ||
| 467 | * to different frame queue using a list of fqids. | ||
| 468 | * @d: the given DPIO service. | ||
| 469 | * @fqid: the given list of frame queue ids. | ||
| 470 | * @fd: the frame descriptor which is enqueued. | ||
| 471 | * @nb: number of frames to be enqueud | ||
| 472 | * | ||
| 473 | * Return 0 for successful enqueue, -EBUSY if the enqueue ring is not ready, | ||
| 474 | * or -ENODEV if there is no dpio service. | ||
| 475 | */ | ||
| 476 | int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d, | ||
| 477 | u32 *fqid, | ||
| 478 | const struct dpaa2_fd *fd, | ||
| 479 | int nb) | ||
| 480 | { | ||
| 481 | int i; | ||
| 482 | struct qbman_eq_desc ed[32]; | ||
| 483 | |||
| 484 | d = service_select(d); | ||
| 485 | if (!d) | ||
| 486 | return -ENODEV; | ||
| 487 | |||
| 488 | for (i = 0; i < nb; i++) { | ||
| 489 | qbman_eq_desc_clear(&ed[i]); | ||
| 490 | qbman_eq_desc_set_no_orp(&ed[i], 0); | ||
| 491 | qbman_eq_desc_set_fq(&ed[i], fqid[i]); | ||
| 492 | } | ||
| 493 | |||
| 494 | return qbman_swp_enqueue_multiple_desc(d->swp, &ed[0], fd, nb); | ||
| 495 | } | ||
| 496 | EXPORT_SYMBOL(dpaa2_io_service_enqueue_multiple_desc_fq); | ||
| 497 | |||
| 435 | /** | 498 | /** |
| 436 | * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD. | 499 | * dpaa2_io_service_enqueue_qd() - Enqueue a frame to a QD. |
| 437 | * @d: the given DPIO service. | 500 | * @d: the given DPIO service. |
| @@ -526,7 +589,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_acquire); · 88 unmodified lines | |||
| 526 | 589 | ||
| 527 | /** | 590 | /** |
| 528 | * dpaa2_io_store_create() - Create the dma memory storage for dequeue result. | 591 | * dpaa2_io_store_create() - Create the dma memory storage for dequeue result. |
| 529 | * @max_frames: the maximum number of dequeued result for frames, must be <= 16. | 592 | * @max_frames: the maximum number of dequeued result for frames, must be <= 32. |
| 530 | * @dev: the device to allow mapping/unmapping the DMAable region. | 593 | * @dev: the device to allow mapping/unmapping the DMAable region. |
| 531 | * | 594 | * |
| 532 | * The size of the storage is "max_frames*sizeof(struct dpaa2_dq)". | 595 | * The size of the storage is "max_frames*sizeof(struct dpaa2_dq)". |
| @@ -541,7 +604,7 @@ struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, · 8 unmodified lines | |||
| 541 | struct dpaa2_io_store *ret; | 604 | struct dpaa2_io_store *ret; |
| 542 | size_t size; | 605 | size_t size; |
| 543 | 606 | ||
| 544 | if (!max_frames || (max_frames > 16)) | 607 | if (!max_frames || (max_frames > 32)) |
| 545 | return NULL; | 608 | return NULL; |
| 546 | 609 | ||
| 547 | ret = kmalloc(sizeof(*ret), GFP_KERNEL); | 610 | ret = kmalloc(sizeof(*ret), GFP_KERNEL); |
| @@ -1,24 +1,18 @@ | |||
| 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) |
| 2 | /* | 2 | /* |
| 3 | * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. | 3 | * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. |
| 4 | * Copyright 2016 NXP | 4 | * Copyright 2016-2019 NXP |
| 5 | * | 5 | * |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <asm/cacheflush.h> | 8 | #include <asm/cacheflush.h> |
| 9 | #include <linux/io.h> | 9 | #include <linux/io.h> |
| 10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
| 11 | #include <linux/spinlock.h> | ||
| 11 | #include <soc/fsl/dpaa2-global.h> | 12 | #include <soc/fsl/dpaa2-global.h> |
| 12 | 13 | ||
| 13 | #include "qbman-portal.h" | 14 | #include "qbman-portal.h" |
| 14 | 15 | ||
| 15 | #define QMAN_REV_4000 0x04000000 | ||
| 16 | #define QMAN_REV_4100 0x04010000 | ||
| 17 | #define QMAN_REV_4101 0x04010001 | ||
| 18 | #define QMAN_REV_5000 0x05000000 | ||
| 19 | |||
| 20 | #define QMAN_REV_MASK 0xffff0000 | ||
| 21 | |||
| 22 | /* All QBMan command and result structures use this "valid bit" encoding */ | 16 | /* All QBMan command and result structures use this "valid bit" encoding */ |
| 23 | #define QB_VALID_BIT ((u32)0x80) | 17 | #define QB_VALID_BIT ((u32)0x80) |
| 24 | 18 | ||
| @@ -28,6 +22,7 @@ · 3 unmodified lines | |||
| 28 | 22 | ||
| 29 | /* CINH register offsets */ | 23 | /* CINH register offsets */ |
| 30 | #define QBMAN_CINH_SWP_EQCR_PI 0x800 | 24 | #define QBMAN_CINH_SWP_EQCR_PI 0x800 |
| 25 | #define QBMAN_CINH_SWP_EQCR_CI 0x840 | ||
| 31 | #define QBMAN_CINH_SWP_EQAR 0x8c0 | 26 | #define QBMAN_CINH_SWP_EQAR 0x8c0 |
| 32 | #define QBMAN_CINH_SWP_CR_RT 0x900 | 27 | #define QBMAN_CINH_SWP_CR_RT 0x900 |
| 33 | #define QBMAN_CINH_SWP_VDQCR_RT 0x940 | 28 | #define QBMAN_CINH_SWP_VDQCR_RT 0x940 |
| @@ -51,6 +46,8 @@ · 17 unmodified lines | |||
| 51 | #define QBMAN_CENA_SWP_CR 0x600 | 46 | #define QBMAN_CENA_SWP_CR 0x600 |
| 52 | #define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1)) | 47 | #define QBMAN_CENA_SWP_RR(vb) (0x700 + ((u32)(vb) >> 1)) |
| 53 | #define QBMAN_CENA_SWP_VDQCR 0x780 | 48 | #define QBMAN_CENA_SWP_VDQCR 0x780 |
| 49 | #define QBMAN_CENA_SWP_EQCR_CI 0x840 | ||
| 50 | #define QBMAN_CENA_SWP_EQCR_CI_MEMBACK 0x1840 | ||
| 54 | 51 | ||
| 55 | /* CENA register offsets in memory-backed mode */ | 52 | /* CENA register offsets in memory-backed mode */ |
| 56 | #define QBMAN_CENA_SWP_DQRR_MEM(n) (0x800 + ((u32)(n) << 6)) | 53 | #define QBMAN_CENA_SWP_DQRR_MEM(n) (0x800 + ((u32)(n) << 6)) |
| @@ -78,6 +75,12 @@ · 21 unmodified lines | |||
| 78 | /* opaque token for static dequeues */ | 75 | /* opaque token for static dequeues */ |
| 79 | #define QMAN_SDQCR_TOKEN 0xbb | 76 | #define QMAN_SDQCR_TOKEN 0xbb |
| 80 | 77 | ||
| 78 | #define QBMAN_EQCR_DCA_IDXMASK 0x0f | ||
| 79 | #define QBMAN_ENQUEUE_FLAG_DCA (1ULL << 31) | ||
| 80 | |||
| 81 | #define EQ_DESC_SIZE_WITHOUT_FD 29 | ||
| 82 | #define EQ_DESC_SIZE_FD_START 32 | ||
| 83 | |||
| 81 | enum qbman_sdqcr_dct { | 84 | enum qbman_sdqcr_dct { |
| 82 | qbman_sdqcr_dct_null = 0, | 85 | qbman_sdqcr_dct_null = 0, |
| 83 | qbman_sdqcr_dct_prio_ics, | 86 | qbman_sdqcr_dct_prio_ics, |
| @@ -90,6 +93,82 @@ enum qbman_sdqcr_fc { · 6 unmodified lines | |||
| 90 | qbman_sdqcr_fc_up_to_3 = 1 | 93 | qbman_sdqcr_fc_up_to_3 = 1 |
| 91 | }; | 94 | }; |
| 92 | 95 | ||
| 96 | /* Internal Function declaration */ | ||
| 97 | static int qbman_swp_enqueue_direct(struct qbman_swp *s, | ||
| 98 | const struct qbman_eq_desc *d, | ||
| 99 | const struct dpaa2_fd *fd); | ||
| 100 | static int qbman_swp_enqueue_mem_back(struct qbman_swp *s, | ||
| 101 | const struct qbman_eq_desc *d, | ||
| 102 | const struct dpaa2_fd *fd); | ||
| 103 | static int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, | ||
| 104 | const struct qbman_eq_desc *d, | ||
| 105 | const struct dpaa2_fd *fd, | ||
| 106 | uint32_t *flags, | ||
| 107 | int num_frames); | ||
| 108 | static int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, | ||
| 109 | const struct qbman_eq_desc *d, | ||
| 110 | const struct dpaa2_fd *fd, | ||
| 111 | uint32_t *flags, | ||
| 112 | int num_frames); | ||
| 113 | static int | ||
| 114 | qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s, | ||
| 115 | const struct qbman_eq_desc *d, | ||
| 116 | const struct dpaa2_fd *fd, | ||
| 117 | int num_frames); | ||
| 118 | static | ||
| 119 | int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s, | ||
| 120 | const struct qbman_eq_desc *d, | ||
| 121 | const struct dpaa2_fd *fd, | ||
| 122 | int num_frames); | ||
| 123 | static int qbman_swp_pull_direct(struct qbman_swp *s, | ||
| 124 | struct qbman_pull_desc *d); | ||
| 125 | static int qbman_swp_pull_mem_back(struct qbman_swp *s, | ||
| 126 | struct qbman_pull_desc *d); | ||
| 127 | |||
| 128 | const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s); | ||
| 129 | const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s); | ||
| 130 | |||
| 131 | static int qbman_swp_release_direct(struct qbman_swp *s, | ||
| 132 | const struct qbman_release_desc *d, | ||
| 133 | const u64 *buffers, | ||
| 134 | unsigned int num_buffers); | ||
| 135 | static int qbman_swp_release_mem_back(struct qbman_swp *s, | ||
| 136 | const struct qbman_release_desc *d, | ||
| 137 | const u64 *buffers, | ||
| 138 | unsigned int num_buffers); | ||
| 139 | |||
| 140 | /* Function pointers */ | ||
| 141 | int (*qbman_swp_enqueue_ptr)(struct qbman_swp *s, | ||
| 142 | const struct qbman_eq_desc *d, | ||
| 143 | const struct dpaa2_fd *fd) | ||
| 144 | = qbman_swp_enqueue_direct; | ||
| 145 | |||
| 146 | int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s, | ||
| 147 | const struct qbman_eq_desc *d, | ||
| 148 | const struct dpaa2_fd *fd, | ||
| 149 | uint32_t *flags, | ||
| 150 | int num_frames) | ||
| 151 | = qbman_swp_enqueue_multiple_direct; | ||
| 152 | |||
| 153 | int | ||
| 154 | (*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s, | ||
| 155 | const struct qbman_eq_desc *d, | ||
| 156 | const struct dpaa2_fd *fd, | ||
| 157 | int num_frames) | ||
| 158 | = qbman_swp_enqueue_multiple_desc_direct; | ||
| 159 | |||
| 160 | int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d) | ||
| 161 | = qbman_swp_pull_direct; | ||
| 162 | |||
| 163 | const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s) | ||
| 164 | = qbman_swp_dqrr_next_direct; | ||
| 165 | |||
| 166 | int (*qbman_swp_release_ptr)(struct qbman_swp *s, | ||
| 167 | const struct qbman_release_desc *d, | ||
| 168 | const u64 *buffers, | ||
| 169 | unsigned int num_buffers) | ||
| 170 | = qbman_swp_release_direct; | ||
| 171 | |||
| 93 | /* Portal Access */ | 172 | /* Portal Access */ |
| 94 | 173 | ||
| 95 | static inline u32 qbman_read_register(struct qbman_swp *p, u32 offset) | 174 | static inline u32 qbman_read_register(struct qbman_swp *p, u32 offset) |
| @@ -146,6 +225,15 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, · 50 unmodified lines | |||
| 146 | 225 | ||
| 147 | #define QMAN_RT_MODE 0x00000100 | 226 | #define QMAN_RT_MODE 0x00000100 |
| 148 | 227 | ||
| 228 | static inline u8 qm_cyc_diff(u8 ringsize, u8 first, u8 last) | ||
| 229 | { | ||
| 230 | /* 'first' is included, 'last' is excluded */ | ||
| 231 | if (first <= last) | ||
| 232 | return last - first; | ||
| 233 | else | ||
| 234 | return (2 * ringsize) - (first - last); | ||
| 235 | } | ||
| 236 | |||
| 149 | /** | 237 | /** |
| 150 | * qbman_swp_init() - Create a functional object representing the given | 238 | * qbman_swp_init() - Create a functional object representing the given |
| 151 | * QBMan portal descriptor. | 239 | * QBMan portal descriptor. |
| @@ -156,11 +244,16 @@ static inline u32 qbman_set_swp_cfg(u8 max_fill, u8 wn, u8 est, u8 rpm, u8 dcm, · 4 unmodified lines | |||
| 156 | */ | 244 | */ |
| 157 | struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) | 245 | struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) |
| 158 | { | 246 | { |
| 159 | struct qbman_swp *p = kmalloc(sizeof(*p), GFP_KERNEL); | 247 | struct qbman_swp *p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 160 | u32 reg; | 248 | u32 reg; |
| 249 | u32 mask_size; | ||
| 250 | u32 eqcr_pi; | ||
| 161 | 251 | ||
| 162 | if (!p) | 252 | if (!p) |
| 163 | return NULL; | 253 | return NULL; |
| 254 | |||
| 255 | spin_lock_init(&p->access_spinlock); | ||
| 256 | |||
| 164 | p->desc = d; | 257 | p->desc = d; |
| 165 | p->mc.valid_bit = QB_VALID_BIT; | 258 | p->mc.valid_bit = QB_VALID_BIT; |
| 166 | p->sdq = 0; | 259 | p->sdq = 0; |
| @@ -186,25 +279,38 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 19 unmodified lines | |||
| 186 | p->addr_cena = d->cena_bar; | 279 | p->addr_cena = d->cena_bar; |
| 187 | p->addr_cinh = d->cinh_bar; | 280 | p->addr_cinh = d->cinh_bar; |
| 188 | 281 | ||
| 189 | if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) | 282 | if ((p->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { |
| 190 | memset(p->addr_cena, 0, 64 * 1024); | ||
| 191 | 283 | ||
| 192 | reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, | 284 | reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, |
| 193 | 1, /* Writes Non-cacheable */ | 285 | 1, /* Writes Non-cacheable */ |
| 194 | 0, /* EQCR_CI stashing threshold */ | 286 | 0, /* EQCR_CI stashing threshold */ |
| 195 | 3, /* RPM: Valid bit mode, RCR in array mode */ | 287 | 3, /* RPM: RCR in array mode */ |
| 196 | 2, /* DCM: Discrete consumption ack mode */ | 288 | 2, /* DCM: Discrete consumption ack */ |
| 197 | 3, /* EPM: Valid bit mode, EQCR in array mode */ | 289 | 2, /* EPM: EQCR in ring mode */ |
| 198 | 1, /* mem stashing drop enable == TRUE */ | 290 | 1, /* mem stashing drop enable enable */ |
| 199 | 1, /* mem stashing priority == TRUE */ | 291 | 1, /* mem stashing priority enable */ |
| 200 | 1, /* mem stashing enable == TRUE */ | 292 | 1, /* mem stashing enable */ |
| 201 | 1, /* dequeue stashing priority == TRUE */ | 293 | 1, /* dequeue stashing priority enable */ |
| 202 | 0, /* dequeue stashing enable == FALSE */ | 294 | 0, /* dequeue stashing enable enable */ |
| 203 | 0); /* EQCR_CI stashing priority == FALSE */ | 295 | 0); /* EQCR_CI stashing priority enable */ |
| 204 | if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) | 296 | } else { |
| 297 | memset(p->addr_cena, 0, 64 * 1024); | ||
| 298 | reg = qbman_set_swp_cfg(p->dqrr.dqrr_size, | ||
| 299 | 1, /* Writes Non-cacheable */ | ||
| 300 | 1, /* EQCR_CI stashing threshold */ | ||
| 301 | 3, /* RPM: RCR in array mode */ | ||
| 302 | 2, /* DCM: Discrete consumption ack */ | ||
| 303 | 0, /* EPM: EQCR in ring mode */ | ||
| 304 | 1, /* mem stashing drop enable */ | ||
| 305 | 1, /* mem stashing priority enable */ | ||
| 306 | 1, /* mem stashing enable */ | ||
| 307 | 1, /* dequeue stashing priority enable */ | ||
| 308 | 0, /* dequeue stashing enable */ | ||
| 309 | 0); /* EQCR_CI stashing priority enable */ | ||
| 205 | reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */ | 310 | reg |= 1 << SWP_CFG_CPBS_SHIFT | /* memory-backed mode */ |
| 206 | 1 << SWP_CFG_VPM_SHIFT | /* VDQCR read triggered mode */ | 311 | 1 << SWP_CFG_VPM_SHIFT | /* VDQCR read triggered mode */ |
| 207 | 1 << SWP_CFG_CPM_SHIFT; /* CR read triggered mode */ | 312 | 1 << SWP_CFG_CPM_SHIFT; /* CR read triggered mode */ |
| 313 | } | ||
| 208 | 314 | ||
| 209 | qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg); | 315 | qbman_write_register(p, QBMAN_CINH_SWP_CFG, reg); |
| 210 | reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG); | 316 | reg = qbman_read_register(p, QBMAN_CINH_SWP_CFG); |
| @@ -225,6 +331,30 @@ struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d) · 14 unmodified lines | |||
| 225 | * applied when dequeues from a specific channel are enabled. | 331 | * applied when dequeues from a specific channel are enabled. |
| 226 | */ | 332 | */ |
| 227 | qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0); | 333 | qbman_write_register(p, QBMAN_CINH_SWP_SDQCR, 0); |
| 334 | |||
| 335 | p->eqcr.pi_ring_size = 8; | ||
| 336 | if ((p->desc->qman_version & QMAN_REV_MASK) >= QMAN_REV_5000) { | ||
| 337 | p->eqcr.pi_ring_size = 32; | ||
| 338 | qbman_swp_enqueue_ptr = | ||
| 339 | qbman_swp_enqueue_mem_back; | ||
| 340 | qbman_swp_enqueue_multiple_ptr = | ||
| 341 | qbman_swp_enqueue_multiple_mem_back; | ||
| 342 | qbman_swp_enqueue_multiple_desc_ptr = | ||
| 343 | qbman_swp_enqueue_multiple_desc_mem_back; | ||
| 344 | qbman_swp_pull_ptr = qbman_swp_pull_mem_back; | ||
| 345 | qbman_swp_dqrr_next_ptr = qbman_swp_dqrr_next_mem_back; | ||
| 346 | qbman_swp_release_ptr = qbman_swp_release_mem_back; | ||
| 347 | } | ||
| 348 | |||
| 349 | for (mask_size = p->eqcr.pi_ring_size; mask_size > 0; mask_size >>= 1) | ||
| 350 | p->eqcr.pi_ci_mask = (p->eqcr.pi_ci_mask << 1) + 1; | ||
| 351 | eqcr_pi = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_PI); | ||
| 352 | p->eqcr.pi = eqcr_pi & p->eqcr.pi_ci_mask; | ||
| 353 | p->eqcr.pi_vb = eqcr_pi & QB_VALID_BIT; | ||
| 354 | p->eqcr.ci = qbman_read_register(p, QBMAN_CINH_SWP_EQCR_CI) | ||
| 355 | & p->eqcr.pi_ci_mask; | ||
| 356 | p->eqcr.available = p->eqcr.pi_ring_size; | ||
| 357 | |||
| 228 | return p; | 358 | return p; |
| 229 | } | 359 | } |
| 230 | 360 | ||
| @@ -378,6 +508,7 @@ enum qb_enqueue_commands { · 147 unmodified lines | |||
| 378 | #define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT 2 | 508 | #define QB_ENQUEUE_CMD_ORP_ENABLE_SHIFT 2 |
| 379 | #define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3 | 509 | #define QB_ENQUEUE_CMD_IRQ_ON_DISPATCH_SHIFT 3 |
| 380 | #define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT 4 | 510 | #define QB_ENQUEUE_CMD_TARGET_TYPE_SHIFT 4 |
| 511 | #define QB_ENQUEUE_CMD_DCA_EN_SHIFT 7 | ||
| 381 | 512 | ||
| 382 | /** | 513 | /** |
| 383 | * qbman_eq_desc_clear() - Clear the contents of a descriptor to | 514 | * qbman_eq_desc_clear() - Clear the contents of a descriptor to |
| @@ -453,8 +584,9 @@ static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p, · 69 unmodified lines | |||
| 453 | QMAN_RT_MODE); | 584 | QMAN_RT_MODE); |
| 454 | } | 585 | } |
| 455 | 586 | ||
| 587 | #define QB_RT_BIT ((u32)0x100) | ||
| 456 | /** | 588 | /** |
| 457 | * qbman_swp_enqueue() - Issue an enqueue command | 589 | * qbman_swp_enqueue_direct() - Issue an enqueue command |
| 458 | * @s: the software portal used for enqueue | 590 | * @s: the software portal used for enqueue |
| 459 | * @d: the enqueue descriptor | 591 | * @d: the enqueue descriptor |
| 460 | * @fd: the frame descriptor to be enqueued | 592 | * @fd: the frame descriptor to be enqueued |
| @@ -464,30 +596,351 @@ static inline void qbman_write_eqcr_am_rt_register(struct qbman_swp *p, · 3 unmodified lines | |||
| 464 | * | 596 | * |
| 465 | * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. | 597 | * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. |
| 466 | */ | 598 | */ |
| 467 | int qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d, | 599 | static |
| 468 | const struct dpaa2_fd *fd) | 600 | int qbman_swp_enqueue_direct(struct qbman_swp *s, |
| 601 | const struct qbman_eq_desc *d, | ||
| 602 | const struct dpaa2_fd *fd) | ||
| 469 | { | 603 | { |
| 470 | struct qbman_eq_desc *p; | 604 | int flags = 0; |
| 471 | u32 eqar = qbman_read_register(s, QBMAN_CINH_SWP_EQAR); | 605 | int ret = qbman_swp_enqueue_multiple_direct(s, d, fd, &flags, 1); |
| 472 | 606 | ||
| 473 | if (!EQAR_SUCCESS(eqar)) | 607 | if (ret >= 0) |
| 474 | return -EBUSY; | 608 | ret = 0; |
| 609 | else | ||
| 610 | ret = -EBUSY; | ||
| 611 | return ret; | ||
| 612 | } | ||
| 613 | |||
| 614 | /** | ||
| 615 | * qbman_swp_enqueue_mem_back() - Issue an enqueue command | ||
| 616 | * @s: the software portal used for enqueue | ||
| 617 | * @d: the enqueue descriptor | ||
| 618 | * @fd: the frame descriptor to be enqueued | ||
| 619 | * | ||
| 620 | * Please note that 'fd' should only be NULL if the "action" of the | ||
| 621 | * descriptor is "orp_hole" or "orp_nesn". | ||
| 622 | * | ||
| 623 | * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. | ||
| 624 | */ | ||
| 625 | static | ||
| 626 | int qbman_swp_enqueue_mem_back(struct qbman_swp *s, | ||
| 627 | const struct qbman_eq_desc *d, | ||
| 628 | const struct dpaa2_fd *fd) | ||
| 629 | { | ||
| 630 | int flags = 0; | ||
| 631 | int ret = qbman_swp_enqueue_multiple_mem_back(s, d, fd, &flags, 1); | ||
| 475 | 632 | ||
| 476 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_EQCR(EQAR_IDX(eqar))); | 633 | if (ret >= 0) |
| 477 | memcpy(&p->dca, &d->dca, 31); | 634 | ret = 0; |
| 478 | memcpy(&p->fd, fd, sizeof(*fd)); | 635 | else |
| 636 | ret = -EBUSY; | ||
| 637 | return ret; | ||
| 638 | } | ||
| 479 | 639 | ||
| 480 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | 640 | /** |
| 481 | /* Set the verb byte, have to substitute in the valid-bit */ | 641 | * qbman_swp_enqueue_multiple_direct() - Issue a multi enqueue command |
| 482 | dma_wmb(); | 642 | * using one enqueue descriptor |
| 483 | p->verb = d->verb | EQAR_VB(eqar); | 643 | * @s: the software portal used for enqueue |
| 484 | } else { | 644 | * @d: the enqueue descriptor |
| 485 | p->verb = d->verb | EQAR_VB(eqar); | 645 | * @fd: table pointer of frame descriptor table to be enqueued |
| 486 | dma_wmb(); | 646 | * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL |
| 487 | qbman_write_eqcr_am_rt_register(s, EQAR_IDX(eqar)); | 647 | * @num_frames: number of fd to be enqueued |
| 648 | * | ||
| 649 | * Return the number of fd enqueued, or a negative error number. | ||
| 650 | */ | ||
| 651 | static | ||
| 652 | int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, | ||
| 653 | const struct qbman_eq_desc *d, | ||
| 654 | const struct dpaa2_fd *fd, | ||
| 655 | uint32_t *flags, | ||
| 656 | int num_frames) | ||
| 657 | { | ||
| 658 | uint32_t *p = NULL; | ||
| 659 | const uint32_t *cl = (uint32_t *)d; | ||
| 660 | uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; | ||
| 661 | int i, num_enqueued = 0; | ||
| 662 | uint64_t addr_cena; | ||
| 663 | |||
| 664 | spin_lock(&s->access_spinlock); | ||
| 665 | half_mask = (s->eqcr.pi_ci_mask>>1); | ||
| 666 | full_mask = s->eqcr.pi_ci_mask; | ||
| 667 | |||
| 668 | if (!s->eqcr.available) { | ||
| 669 | eqcr_ci = s->eqcr.ci; | ||
| 670 | p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI; | ||
| 671 | s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); | ||
| 672 | |||
| 673 | s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, | ||
| 674 | eqcr_ci, s->eqcr.ci); | ||
| 675 | if (!s->eqcr.available) { | ||
| 676 | spin_unlock(&s->access_spinlock); | ||
| 677 | return 0; | ||
| 678 | } | ||
| 488 | } | 679 | } |
| 489 | 680 | ||
| 490 | return 0; | 681 | eqcr_pi = s->eqcr.pi; |
| 682 | num_enqueued = (s->eqcr.available < num_frames) ? | ||
| 683 | s->eqcr.available : num_frames; | ||
| 684 | s->eqcr.available -= num_enqueued; | ||
| 685 | /* Fill in the EQCR ring */ | ||
| 686 | for (i = 0; i < num_enqueued; i++) { | ||
| 687 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 688 | /* Skip copying the verb */ | ||
| 689 | memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); | ||
| 690 | memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], | ||
| 691 | &fd[i], sizeof(*fd)); | ||
| 692 | eqcr_pi++; | ||
| 693 | } | ||
| 694 | |||
| 695 | dma_wmb(); | ||
| 696 | |||
| 697 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 698 | eqcr_pi = s->eqcr.pi; | ||
| 699 | for (i = 0; i < num_enqueued; i++) { | ||
| 700 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 701 | p[0] = cl[0] | s->eqcr.pi_vb; | ||
| 702 | if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { | ||
| 703 | struct qbman_eq_desc *d = (struct qbman_eq_desc *)p; | ||
| 704 | |||
| 705 | d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | | ||
| 706 | ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); | ||
| 707 | } | ||
| 708 | eqcr_pi++; | ||
| 709 | if (!(eqcr_pi & half_mask)) | ||
| 710 | s->eqcr.pi_vb ^= QB_VALID_BIT; | ||
| 711 | } | ||
| 712 | |||
| 713 | /* Flush all the cacheline without load/store in between */ | ||
| 714 | eqcr_pi = s->eqcr.pi; | ||
| 715 | addr_cena = (size_t)s->addr_cena; | ||
| 716 | for (i = 0; i < num_enqueued; i++) | ||
| 717 | eqcr_pi++; | ||
| 718 | s->eqcr.pi = eqcr_pi & full_mask; | ||
| 719 | spin_unlock(&s->access_spinlock); | ||
| 720 | |||
| 721 | return num_enqueued; | ||
| 722 | } | ||
| 723 | |||
| 724 | /** | ||
| 725 | * qbman_swp_enqueue_multiple_mem_back() - Issue a multi enqueue command | ||
| 726 | * using one enqueue descriptor | ||
| 727 | * @s: the software portal used for enqueue | ||
| 728 | * @d: the enqueue descriptor | ||
| 729 | * @fd: table pointer of frame descriptor table to be enqueued | ||
| 730 | * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL | ||
| 731 | * @num_frames: number of fd to be enqueued | ||
| 732 | * | ||
| 733 | * Return the number of fd enqueued, or a negative error number. | ||
| 734 | */ | ||
| 735 | static | ||
| 736 | int qbman_swp_enqueue_multiple_mem_back(struct qbman_swp *s, | ||
| 737 | const struct qbman_eq_desc *d, | ||
| 738 | const struct dpaa2_fd *fd, | ||
| 739 | uint32_t *flags, | ||
| 740 | int num_frames) | ||
| 741 | { | ||
| 742 | uint32_t *p = NULL; | ||
| 743 | const uint32_t *cl = (uint32_t *)(d); | ||
| 744 | uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; | ||
| 745 | int i, num_enqueued = 0; | ||
| 746 | unsigned long irq_flags; | ||
| 747 | |||
| 748 | spin_lock(&s->access_spinlock); | ||
| 749 | local_irq_save(irq_flags); | ||
| 750 | |||
| 751 | half_mask = (s->eqcr.pi_ci_mask>>1); | ||
| 752 | full_mask = s->eqcr.pi_ci_mask; | ||
| 753 | if (!s->eqcr.available) { | ||
| 754 | eqcr_ci = s->eqcr.ci; | ||
| 755 | p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK; | ||
| 756 | s->eqcr.ci = __raw_readl(p) & full_mask; | ||
| 757 | s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, | ||
| 758 | eqcr_ci, s->eqcr.ci); | ||
| 759 | if (!s->eqcr.available) { | ||
| 760 | local_irq_restore(irq_flags); | ||
| 761 | spin_unlock(&s->access_spinlock); | ||
| 762 | return 0; | ||
| 763 | } | ||
| 764 | } | ||
| 765 | |||
| 766 | eqcr_pi = s->eqcr.pi; | ||
| 767 | num_enqueued = (s->eqcr.available < num_frames) ? | ||
| 768 | s->eqcr.available : num_frames; | ||
| 769 | s->eqcr.available -= num_enqueued; | ||
| 770 | /* Fill in the EQCR ring */ | ||
| 771 | for (i = 0; i < num_enqueued; i++) { | ||
| 772 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 773 | /* Skip copying the verb */ | ||
| 774 | memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); | ||
| 775 | memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], | ||
| 776 | &fd[i], sizeof(*fd)); | ||
| 777 | eqcr_pi++; | ||
| 778 | } | ||
| 779 | |||
| 780 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 781 | eqcr_pi = s->eqcr.pi; | ||
| 782 | for (i = 0; i < num_enqueued; i++) { | ||
| 783 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 784 | p[0] = cl[0] | s->eqcr.pi_vb; | ||
| 785 | if (flags && (flags[i] & QBMAN_ENQUEUE_FLAG_DCA)) { | ||
| 786 | struct qbman_eq_desc *d = (struct qbman_eq_desc *)p; | ||
| 787 | |||
| 788 | d->dca = (1 << QB_ENQUEUE_CMD_DCA_EN_SHIFT) | | ||
| 789 | ((flags[i]) & QBMAN_EQCR_DCA_IDXMASK); | ||
| 790 | } | ||
| 791 | eqcr_pi++; | ||
| 792 | if (!(eqcr_pi & half_mask)) | ||
| 793 | s->eqcr.pi_vb ^= QB_VALID_BIT; | ||
| 794 | } | ||
| 795 | s->eqcr.pi = eqcr_pi & full_mask; | ||
| 796 | |||
| 797 | dma_wmb(); | ||
| 798 | qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI, | ||
| 799 | (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb); | ||
| 800 | local_irq_restore(irq_flags); | ||
| 801 | spin_unlock(&s->access_spinlock); | ||
| 802 | |||
| 803 | return num_enqueued; | ||
| 804 | } | ||
| 805 | |||
| 806 | /** | ||
| 807 | * qbman_swp_enqueue_multiple_desc_direct() - Issue a multi enqueue command | ||
| 808 | * using multiple enqueue descriptor | ||
| 809 | * @s: the software portal used for enqueue | ||
| 810 | * @d: table of minimal enqueue descriptor | ||
| 811 | * @fd: table pointer of frame descriptor table to be enqueued | ||
| 812 | * @num_frames: number of fd to be enqueued | ||
| 813 | * | ||
| 814 | * Return the number of fd enqueued, or a negative error number. | ||
| 815 | */ | ||
| 816 | static | ||
| 817 | int qbman_swp_enqueue_multiple_desc_direct(struct qbman_swp *s, | ||
| 818 | const struct qbman_eq_desc *d, | ||
| 819 | const struct dpaa2_fd *fd, | ||
| 820 | int num_frames) | ||
| 821 | { | ||
| 822 | uint32_t *p; | ||
| 823 | const uint32_t *cl; | ||
| 824 | uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; | ||
| 825 | int i, num_enqueued = 0; | ||
| 826 | uint64_t addr_cena; | ||
| 827 | |||
| 828 | half_mask = (s->eqcr.pi_ci_mask>>1); | ||
| 829 | full_mask = s->eqcr.pi_ci_mask; | ||
| 830 | if (!s->eqcr.available) { | ||
| 831 | eqcr_ci = s->eqcr.ci; | ||
| 832 | p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI; | ||
| 833 | s->eqcr.ci = qbman_read_register(s, QBMAN_CINH_SWP_EQCR_CI); | ||
| 834 | s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, | ||
| 835 | eqcr_ci, s->eqcr.ci); | ||
| 836 | if (!s->eqcr.available) | ||
| 837 | return 0; | ||
| 838 | } | ||
| 839 | |||
| 840 | eqcr_pi = s->eqcr.pi; | ||
| 841 | num_enqueued = (s->eqcr.available < num_frames) ? | ||
| 842 | s->eqcr.available : num_frames; | ||
| 843 | s->eqcr.available -= num_enqueued; | ||
| 844 | /* Fill in the EQCR ring */ | ||
| 845 | for (i = 0; i < num_enqueued; i++) { | ||
| 846 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 847 | cl = (uint32_t *)(&d[i]); | ||
| 848 | /* Skip copying the verb */ | ||
| 849 | memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); | ||
| 850 | memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], | ||
| 851 | &fd[i], sizeof(*fd)); | ||
| 852 | eqcr_pi++; | ||
| 853 | } | ||
| 854 | |||
| 855 | dma_wmb(); | ||
| 856 | |||
| 857 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 858 | eqcr_pi = s->eqcr.pi; | ||
| 859 | for (i = 0; i < num_enqueued; i++) { | ||
| 860 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 861 | cl = (uint32_t *)(&d[i]); | ||
| 862 | p[0] = cl[0] | s->eqcr.pi_vb; | ||
| 863 | eqcr_pi++; | ||
| 864 | if (!(eqcr_pi & half_mask)) | ||
| 865 | s->eqcr.pi_vb ^= QB_VALID_BIT; | ||
| 866 | } | ||
| 867 | |||
| 868 | /* Flush all the cacheline without load/store in between */ | ||
| 869 | eqcr_pi = s->eqcr.pi; | ||
| 870 | addr_cena = (uint64_t)s->addr_cena; | ||
| 871 | for (i = 0; i < num_enqueued; i++) | ||
| 872 | eqcr_pi++; | ||
| 873 | s->eqcr.pi = eqcr_pi & full_mask; | ||
| 874 | |||
| 875 | return num_enqueued; | ||
| 876 | } | ||
| 877 | |||
| 878 | /** | ||
| 879 | * qbman_swp_enqueue_multiple_desc_mem_back() - Issue a multi enqueue command | ||
| 880 | * using multiple enqueue descriptor | ||
| 881 | * @s: the software portal used for enqueue | ||
| 882 | * @d: table of minimal enqueue descriptor | ||
| 883 | * @fd: table pointer of frame descriptor table to be enqueued | ||
| 884 | * @num_frames: number of fd to be enqueued | ||
| 885 | * | ||
| 886 | * Return the number of fd enqueued, or a negative error number. | ||
| 887 | */ | ||
| 888 | static | ||
| 889 | int qbman_swp_enqueue_multiple_desc_mem_back(struct qbman_swp *s, | ||
| 890 | const struct qbman_eq_desc *d, | ||
| 891 | const struct dpaa2_fd *fd, | ||
| 892 | int num_frames) | ||
| 893 | { | ||
| 894 | uint32_t *p; | ||
| 895 | const uint32_t *cl; | ||
| 896 | uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; | ||
| 897 | int i, num_enqueued = 0; | ||
| 898 | |||
| 899 | half_mask = (s->eqcr.pi_ci_mask>>1); | ||
| 900 | full_mask = s->eqcr.pi_ci_mask; | ||
| 901 | if (!s->eqcr.available) { | ||
| 902 | eqcr_ci = s->eqcr.ci; | ||
| 903 | p = s->addr_cena + QBMAN_CENA_SWP_EQCR_CI_MEMBACK; | ||
| 904 | s->eqcr.ci = __raw_readl(p) & full_mask; | ||
| 905 | s->eqcr.available = qm_cyc_diff(s->eqcr.pi_ring_size, | ||
| 906 | eqcr_ci, s->eqcr.ci); | ||
| 907 | if (!s->eqcr.available) | ||
| 908 | return 0; | ||
| 909 | } | ||
| 910 | |||
| 911 | eqcr_pi = s->eqcr.pi; | ||
| 912 | num_enqueued = (s->eqcr.available < num_frames) ? | ||
| 913 | s->eqcr.available : num_frames; | ||
| 914 | s->eqcr.available -= num_enqueued; | ||
| 915 | /* Fill in the EQCR ring */ | ||
| 916 | for (i = 0; i < num_enqueued; i++) { | ||
| 917 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 918 | cl = (uint32_t *)(&d[i]); | ||
| 919 | /* Skip copying the verb */ | ||
| 920 | memcpy(&p[1], &cl[1], EQ_DESC_SIZE_WITHOUT_FD - 1); | ||
| 921 | memcpy(&p[EQ_DESC_SIZE_FD_START/sizeof(uint32_t)], | ||
| 922 | &fd[i], sizeof(*fd)); | ||
| 923 | eqcr_pi++; | ||
| 924 | } | ||
| 925 | |||
| 926 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 927 | eqcr_pi = s->eqcr.pi; | ||
| 928 | for (i = 0; i < num_enqueued; i++) { | ||
| 929 | p = (s->addr_cena + QBMAN_CENA_SWP_EQCR(eqcr_pi & half_mask)); | ||
| 930 | cl = (uint32_t *)(&d[i]); | ||
| 931 | p[0] = cl[0] | s->eqcr.pi_vb; | ||
| 932 | eqcr_pi++; | ||
| 933 | if (!(eqcr_pi & half_mask)) | ||
| 934 | s->eqcr.pi_vb ^= QB_VALID_BIT; | ||
| 935 | } | ||
| 936 | |||
| 937 | s->eqcr.pi = eqcr_pi & full_mask; | ||
| 938 | |||
| 939 | dma_wmb(); | ||
| 940 | qbman_write_register(s, QBMAN_CINH_SWP_EQCR_PI, | ||
| 941 | (QB_RT_BIT)|(s->eqcr.pi)|s->eqcr.pi_vb); | ||
| 942 | |||
| 943 | return num_enqueued; | ||
| 491 | } | 944 | } |
| 492 | 945 | ||
| 493 | /* Static (push) dequeue */ | 946 | /* Static (push) dequeue */ |
| @@ -645,7 +1098,7 @@ void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, · 151 unmodified lines | |||
| 645 | } | 1098 | } |
| 646 | 1099 | ||
| 647 | /** | 1100 | /** |
| 648 | * qbman_swp_pull() - Issue the pull dequeue command | 1101 | * qbman_swp_pull_direct() - Issue the pull dequeue command |
| 649 | * @s: the software portal object | 1102 | * @s: the software portal object |
| 650 | * @d: the software portal descriptor which has been configured with | 1103 | * @d: the software portal descriptor which has been configured with |
| 651 | * the set of qbman_pull_desc_set_*() calls | 1104 | * the set of qbman_pull_desc_set_*() calls |
| @@ -653,7 +1106,8 @@ void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, · 1 unmodified line | |||
| 653 | * Return 0 for success, and -EBUSY if the software portal is not ready | 1106 | * Return 0 for success, and -EBUSY if the software portal is not ready |
| 654 | * to do pull dequeue. | 1107 | * to do pull dequeue. |
| 655 | */ | 1108 | */ |
| 656 | int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) | 1109 | static |
| 1110 | int qbman_swp_pull_direct(struct qbman_swp *s, struct qbman_pull_desc *d) | ||
| 657 | { | 1111 | { |
| 658 | struct qbman_pull_desc *p; | 1112 | struct qbman_pull_desc *p; |
| 659 | 1113 | ||
| @@ -671,18 +1125,48 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) · 11 unmodified lines | |||
| 671 | p->dq_src = d->dq_src; | 1125 | p->dq_src = d->dq_src; |
| 672 | p->rsp_addr = d->rsp_addr; | 1126 | p->rsp_addr = d->rsp_addr; |
| 673 | p->rsp_addr_virt = d->rsp_addr_virt; | 1127 | p->rsp_addr_virt = d->rsp_addr_virt; |
| 1128 | dma_wmb(); | ||
| 1129 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 1130 | p->verb = d->verb | s->vdq.valid_bit; | ||
| 1131 | s->vdq.valid_bit ^= QB_VALID_BIT; | ||
| 674 | 1132 | ||
| 675 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | 1133 | return 0; |
| 676 | dma_wmb(); | 1134 | } |
| 677 | /* Set the verb byte, have to substitute in the valid-bit */ | 1135 | |
| 678 | p->verb = d->verb | s->vdq.valid_bit; | 1136 | /** |
| 679 | s->vdq.valid_bit ^= QB_VALID_BIT; | 1137 | * qbman_swp_pull_mem_back() - Issue the pull dequeue command |
| 680 | } else { | 1138 | * @s: the software portal object |
| 681 | p->verb = d->verb | s->vdq.valid_bit; | 1139 | * @d: the software portal descriptor which has been configured with |
| 682 | s->vdq.valid_bit ^= QB_VALID_BIT; | 1140 | * the set of qbman_pull_desc_set_*() calls |
| 683 | dma_wmb(); | 1141 | * |
| 684 | qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE); | 1142 | * Return 0 for success, and -EBUSY if the software portal is not ready |
| 1143 | * to do pull dequeue. | ||
| 1144 | */ | ||
| 1145 | static | ||
| 1146 | int qbman_swp_pull_mem_back(struct qbman_swp *s, struct qbman_pull_desc *d) | ||
| 1147 | { | ||
| 1148 | struct qbman_pull_desc *p; | ||
| 1149 | |||
| 1150 | if (!atomic_dec_and_test(&s->vdq.available)) { | ||
| 1151 | atomic_inc(&s->vdq.available); | ||
| 1152 | return -EBUSY; | ||
| 685 | } | 1153 | } |
| 1154 | s->vdq.storage = (void *)(uintptr_t)d->rsp_addr_virt; | ||
| 1155 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | ||
| 1156 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR); | ||
| 1157 | else | ||
| 1158 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_VDQCR_MEM); | ||
| 1159 | p->numf = d->numf; | ||
| 1160 | p->tok = QMAN_DQ_TOKEN_VALID; | ||
| 1161 | p->dq_src = d->dq_src; | ||
| 1162 | p->rsp_addr = d->rsp_addr; | ||
| 1163 | p->rsp_addr_virt = d->rsp_addr_virt; | ||
| 1164 | |||
| 1165 | /* Set the verb byte, have to substitute in the valid-bit */ | ||
| 1166 | p->verb = d->verb | s->vdq.valid_bit; | ||
| 1167 | s->vdq.valid_bit ^= QB_VALID_BIT; | ||
| 1168 | dma_wmb(); | ||
| 1169 | qbman_write_register(s, QBMAN_CINH_SWP_VDQCR_RT, QMAN_RT_MODE); | ||
| 686 | 1170 | ||
| 687 | return 0; | 1171 | return 0; |
| 688 | } | 1172 | } |
| @@ -690,14 +1174,14 @@ int qbman_swp_pull(struct qbman_swp *s, struct qbman_pull_desc *d) · 1 unmodified line | |||
| 690 | #define QMAN_DQRR_PI_MASK 0xf | 1174 | #define QMAN_DQRR_PI_MASK 0xf |
| 691 | 1175 | ||
| 692 | /** | 1176 | /** |
| 693 | * qbman_swp_dqrr_next() - Get an valid DQRR entry | 1177 | * qbman_swp_dqrr_next_direct() - Get an valid DQRR entry |
| 694 | * @s: the software portal object | 1178 | * @s: the software portal object |
| 695 | * | 1179 | * |
| 696 | * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry | 1180 | * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry |
| 697 | * only once, so repeated calls can return a sequence of DQRR entries, without | 1181 | * only once, so repeated calls can return a sequence of DQRR entries, without |
| 698 | * requiring they be consumed immediately or in any particular order. | 1182 | * requiring they be consumed immediately or in any particular order. |
| 699 | */ | 1183 | */ |
| 700 | const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s) | 1184 | const struct dpaa2_dq *qbman_swp_dqrr_next_direct(struct qbman_swp *s) |
| 701 | { | 1185 | { |
| 702 | u32 verb; | 1186 | u32 verb; |
| 703 | u32 response_verb; | 1187 | u32 response_verb; |
| @@ -740,10 +1224,99 @@ const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s) · 36 unmodified lines | |||
| 740 | QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); | 1224 | QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); |
| 741 | } | 1225 | } |
| 742 | 1226 | ||
| 743 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | 1227 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); |
| 744 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx)); | 1228 | verb = p->dq.verb; |
| 745 | else | 1229 | |
| 746 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx)); | 1230 | /* |
| 1231 | * If the valid-bit isn't of the expected polarity, nothing there. Note, | ||
| 1232 | * in the DQRR reset bug workaround, we shouldn't need to skip these | ||
| 1233 | * check, because we've already determined that a new entry is available | ||
| 1234 | * and we've invalidated the cacheline before reading it, so the | ||
| 1235 | * valid-bit behaviour is repaired and should tell us what we already | ||
| 1236 | * knew from reading PI. | ||
| 1237 | */ | ||
| 1238 | if ((verb & QB_VALID_BIT) != s->dqrr.valid_bit) { | ||
| 1239 | prefetch(qbman_get_cmd(s, | ||
| 1240 | QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); | ||
| 1241 | return NULL; | ||
| 1242 | } | ||
| 1243 | /* | ||
| 1244 | * There's something there. Move "next_idx" attention to the next ring | ||
| 1245 | * entry (and prefetch it) before returning what we found. | ||
| 1246 | */ | ||
| 1247 | s->dqrr.next_idx++; | ||
| 1248 | s->dqrr.next_idx &= s->dqrr.dqrr_size - 1; /* Wrap around */ | ||
| 1249 | if (!s->dqrr.next_idx) | ||
| 1250 | s->dqrr.valid_bit ^= QB_VALID_BIT; | ||
| 1251 | |||
| 1252 | /* | ||
| 1253 | * If this is the final response to a volatile dequeue command | ||
| 1254 | * indicate that the vdq is available | ||
| 1255 | */ | ||
| 1256 | flags = p->dq.stat; | ||
| 1257 | response_verb = verb & QBMAN_RESULT_MASK; | ||
| 1258 | if ((response_verb == QBMAN_RESULT_DQ) && | ||
| 1259 | (flags & DPAA2_DQ_STAT_VOLATILE) && | ||
| 1260 | (flags & DPAA2_DQ_STAT_EXPIRED)) | ||
| 1261 | atomic_inc(&s->vdq.available); | ||
| 1262 | |||
| 1263 | prefetch(qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); | ||
| 1264 | |||
| 1265 | return p; | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | /** | ||
| 1269 | * qbman_swp_dqrr_next_mem_back() - Get an valid DQRR entry | ||
| 1270 | * @s: the software portal object | ||
| 1271 | * | ||
| 1272 | * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry | ||
| 1273 | * only once, so repeated calls can return a sequence of DQRR entries, without | ||
| 1274 | * requiring they be consumed immediately or in any particular order. | ||
| 1275 | */ | ||
| 1276 | const struct dpaa2_dq *qbman_swp_dqrr_next_mem_back(struct qbman_swp *s) | ||
| 1277 | { | ||
| 1278 | u32 verb; | ||
| 1279 | u32 response_verb; | ||
| 1280 | u32 flags; | ||
| 1281 | struct dpaa2_dq *p; | ||
| 1282 | |||
| 1283 | /* Before using valid-bit to detect if something is there, we have to | ||
| 1284 | * handle the case of the DQRR reset bug... | ||
| 1285 | */ | ||
| 1286 | if (unlikely(s->dqrr.reset_bug)) { | ||
| 1287 | /* | ||
| 1288 | * We pick up new entries by cache-inhibited producer index, | ||
| 1289 | * which means that a non-coherent mapping would require us to | ||
| 1290 | * invalidate and read *only* once that PI has indicated that | ||
| 1291 | * there's an entry here. The first trip around the DQRR ring | ||
| 1292 | * will be much less efficient than all subsequent trips around | ||
| 1293 | * it... | ||
| 1294 | */ | ||
| 1295 | u8 pi = qbman_read_register(s, QBMAN_CINH_SWP_DQPI) & | ||
| 1296 | QMAN_DQRR_PI_MASK; | ||
| 1297 | |||
| 1298 | /* there are new entries if pi != next_idx */ | ||
| 1299 | if (pi == s->dqrr.next_idx) | ||
| 1300 | return NULL; | ||
| 1301 | |||
| 1302 | /* | ||
| 1303 | * if next_idx is/was the last ring index, and 'pi' is | ||
| 1304 | * different, we can disable the workaround as all the ring | ||
| 1305 | * entries have now been DMA'd to so valid-bit checking is | ||
| 1306 | * repaired. Note: this logic needs to be based on next_idx | ||
| 1307 | * (which increments one at a time), rather than on pi (which | ||
| 1308 | * can burst and wrap-around between our snapshots of it). | ||
| 1309 | */ | ||
| 1310 | if (s->dqrr.next_idx == (s->dqrr.dqrr_size - 1)) { | ||
| 1311 | pr_debug("next_idx=%d, pi=%d, clear reset bug\n", | ||
| 1312 | s->dqrr.next_idx, pi); | ||
| 1313 | s->dqrr.reset_bug = 0; | ||
| 1314 | } | ||
| 1315 | prefetch(qbman_get_cmd(s, | ||
| 1316 | QBMAN_CENA_SWP_DQRR(s->dqrr.next_idx))); | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_DQRR_MEM(s->dqrr.next_idx)); | ||
| 747 | verb = p->dq.verb; | 1320 | verb = p->dq.verb; |
| 748 | 1321 | ||
| 749 | /* | 1322 | /* |
| @@ -872,7 +1445,7 @@ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable) · 122 unmodified lines | |||
| 872 | #define RAR_SUCCESS(rar) ((rar) & 0x100) | 1445 | #define RAR_SUCCESS(rar) ((rar) & 0x100) |
| 873 | 1446 | ||
| 874 | /** | 1447 | /** |
| 875 | * qbman_swp_release() - Issue a buffer release command | 1448 | * qbman_swp_release_direct() - Issue a buffer release command |
| 876 | * @s: the software portal object | 1449 | * @s: the software portal object |
| 877 | * @d: the release descriptor | 1450 | * @d: the release descriptor |
| 878 | * @buffers: a pointer pointing to the buffer address to be released | 1451 | * @buffers: a pointer pointing to the buffer address to be released |
| @@ -880,8 +1453,9 @@ void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable) · 1 unmodified line | |||
| 880 | * | 1453 | * |
| 881 | * Return 0 for success, -EBUSY if the release command ring is not ready. | 1454 | * Return 0 for success, -EBUSY if the release command ring is not ready. |
| 882 | */ | 1455 | */ |
| 883 | int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, | 1456 | int qbman_swp_release_direct(struct qbman_swp *s, |
| 884 | const u64 *buffers, unsigned int num_buffers) | 1457 | const struct qbman_release_desc *d, |
| 1458 | const u64 *buffers, unsigned int num_buffers) | ||
| 885 | { | 1459 | { |
| 886 | int i; | 1460 | int i; |
| 887 | struct qbman_release_desc *p; | 1461 | struct qbman_release_desc *p; |
| @@ -895,28 +1469,59 @@ int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, · 7 unmodified lines | |||
| 895 | return -EBUSY; | 1469 | return -EBUSY; |
| 896 | 1470 | ||
| 897 | /* Start the release command */ | 1471 | /* Start the release command */ |
| 898 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) | 1472 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); |
| 899 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR(RAR_IDX(rar))); | 1473 | |
| 900 | else | ||
| 901 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar))); | ||
| 902 | /* Copy the caller's buffer pointers to the command */ | 1474 | /* Copy the caller's buffer pointers to the command */ |
| 903 | for (i = 0; i < num_buffers; i++) | 1475 | for (i = 0; i < num_buffers; i++) |
| 904 | p->buf[i] = cpu_to_le64(buffers[i]); | 1476 | p->buf[i] = cpu_to_le64(buffers[i]); |
| 905 | p->bpid = d->bpid; | 1477 | p->bpid = d->bpid; |
| 906 | 1478 | ||
| 907 | if ((s->desc->qman_version & QMAN_REV_MASK) < QMAN_REV_5000) { | 1479 | /* |
| 908 | /* | 1480 | * Set the verb byte, have to substitute in the valid-bit |
| 909 | * Set the verb byte, have to substitute in the valid-bit | 1481 | * and the number of buffers. |
| 910 | * and the number of buffers. | 1482 | */ |
| 911 | */ | 1483 | dma_wmb(); |
| 912 | dma_wmb(); | 1484 | p->verb = d->verb | RAR_VB(rar) | num_buffers; |
| 913 | p->verb = d->verb | RAR_VB(rar) | num_buffers; | 1485 | |
| 914 | } else { | 1486 | return 0; |
| 915 | p->verb = d->verb | RAR_VB(rar) | num_buffers; | 1487 | } |
| 916 | dma_wmb(); | 1488 | |
| 917 | qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT + | 1489 | /** |
| 918 | RAR_IDX(rar) * 4, QMAN_RT_MODE); | 1490 | * qbman_swp_release_mem_back() - Issue a buffer release command |
| 919 | } | 1491 | * @s: the software portal object |
| 1492 | * @d: the release descriptor | ||
| 1493 | * @buffers: a pointer pointing to the buffer address to be released | ||
| 1494 | * @num_buffers: number of buffers to be released, must be less than 8 | ||
| 1495 | * | ||
| 1496 | * Return 0 for success, -EBUSY if the release command ring is not ready. | ||
| 1497 | */ | ||
| 1498 | int qbman_swp_release_mem_back(struct qbman_swp *s, | ||
| 1499 | const struct qbman_release_desc *d, | ||
| 1500 | const u64 *buffers, unsigned int num_buffers) | ||
| 1501 | { | ||
| 1502 | int i; | ||
| 1503 | struct qbman_release_desc *p; | ||
| 1504 | u32 rar; | ||
| 1505 | |||
| 1506 | if (!num_buffers || (num_buffers > 7)) | ||
| 1507 | return -EINVAL; | ||
| 1508 | |||
| 1509 | rar = qbman_read_register(s, QBMAN_CINH_SWP_RAR); | ||
| 1510 | if (!RAR_SUCCESS(rar)) | ||
| 1511 | return -EBUSY; | ||
| 1512 | |||
| 1513 | /* Start the release command */ | ||
| 1514 | p = qbman_get_cmd(s, QBMAN_CENA_SWP_RCR_MEM(RAR_IDX(rar))); | ||
| 1515 | |||
| 1516 | /* Copy the caller's buffer pointers to the command */ | ||
| 1517 | for (i = 0; i < num_buffers; i++) | ||
| 1518 | p->buf[i] = cpu_to_le64(buffers[i]); | ||
| 1519 | p->bpid = d->bpid; | ||
| 1520 | |||
| 1521 | p->verb = d->verb | RAR_VB(rar) | num_buffers; | ||
| 1522 | dma_wmb(); | ||
| 1523 | qbman_write_register(s, QBMAN_CINH_SWP_RCR_AM_RT + | ||
| 1524 | RAR_IDX(rar) * 4, QMAN_RT_MODE); | ||
| 920 | 1525 | ||
| 921 | return 0; | 1526 | return 0; |
| 922 | } | 1527 | } |
| @@ -9,6 +9,13 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <soc/fsl/dpaa2-fd.h> | 10 | #include <soc/fsl/dpaa2-fd.h> |
| 11 | 11 | ||
| 12 | #define QMAN_REV_4000 0x04000000 | ||
| 13 | #define QMAN_REV_4100 0x04010000 | ||
| 14 | #define QMAN_REV_4101 0x04010001 | ||
| 15 | #define QMAN_REV_5000 0x05000000 | ||
| 16 | |||
| 17 | #define QMAN_REV_MASK 0xffff0000 | ||
| 18 | |||
| 12 | struct dpaa2_dq; | 19 | struct dpaa2_dq; |
| 13 | struct qbman_swp; | 20 | struct qbman_swp; |
| 14 | 21 | ||
| @@ -81,6 +88,10 @@ struct qbman_eq_desc { · 66 unmodified lines | |||
| 81 | u8 wae; | 88 | u8 wae; |
| 82 | u8 rspid; | 89 | u8 rspid; |
| 83 | __le64 rsp_addr; | 90 | __le64 rsp_addr; |
| 91 | }; | ||
| 92 | |||
| 93 | struct qbman_eq_desc_with_fd { | ||
| 94 | struct qbman_eq_desc desc; | ||
| 84 | u8 fd[32]; | 95 | u8 fd[32]; |
| 85 | }; | 96 | }; |
| 86 | 97 | ||
| @@ -132,8 +143,48 @@ struct qbman_swp { · 45 unmodified lines | |||
| 132 | u8 dqrr_size; | 143 | u8 dqrr_size; |
| 133 | int reset_bug; /* indicates dqrr reset workaround is needed */ | 144 | int reset_bug; /* indicates dqrr reset workaround is needed */ |
| 134 | } dqrr; | 145 | } dqrr; |
| 146 | |||
| 147 | struct { | ||
| 148 | u32 pi; | ||
| 149 | u32 pi_vb; | ||
| 150 | u32 pi_ring_size; | ||
| 151 | u32 pi_ci_mask; | ||
| 152 | u32 ci; | ||
| 153 | int available; | ||
| 154 | u32 pend; | ||
| 155 | u32 no_pfdr; | ||
| 156 | } eqcr; | ||
| 157 | |||
| 158 | spinlock_t access_spinlock; | ||
| 135 | }; | 159 | }; |
| 136 | 160 | ||
| 161 | /* Function pointers */ | ||
| 162 | extern | ||
| 163 | int (*qbman_swp_enqueue_ptr)(struct qbman_swp *s, | ||
| 164 | const struct qbman_eq_desc *d, | ||
| 165 | const struct dpaa2_fd *fd); | ||
| 166 | extern | ||
| 167 | int (*qbman_swp_enqueue_multiple_ptr)(struct qbman_swp *s, | ||
| 168 | const struct qbman_eq_desc *d, | ||
| 169 | const struct dpaa2_fd *fd, | ||
| 170 | uint32_t *flags, | ||
| 171 | int num_frames); | ||
| 172 | extern | ||
| 173 | int (*qbman_swp_enqueue_multiple_desc_ptr)(struct qbman_swp *s, | ||
| 174 | const struct qbman_eq_desc *d, | ||
| 175 | const struct dpaa2_fd *fd, | ||
| 176 | int num_frames); | ||
| 177 | extern | ||
| 178 | int (*qbman_swp_pull_ptr)(struct qbman_swp *s, struct qbman_pull_desc *d); | ||
| 179 | extern | ||
| 180 | const struct dpaa2_dq *(*qbman_swp_dqrr_next_ptr)(struct qbman_swp *s); | ||
| 181 | extern | ||
| 182 | int (*qbman_swp_release_ptr)(struct qbman_swp *s, | ||
| 183 | const struct qbman_release_desc *d, | ||
| 184 | const u64 *buffers, | ||
| 185 | unsigned int num_buffers); | ||
| 186 | |||
| 187 | /* Functions */ | ||
| 137 | struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d); | 188 | struct qbman_swp *qbman_swp_init(const struct qbman_swp_desc *d); |
| 138 | void qbman_swp_finish(struct qbman_swp *p); | 189 | void qbman_swp_finish(struct qbman_swp *p); |
| 139 | u32 qbman_swp_interrupt_read_status(struct qbman_swp *p); | 190 | u32 qbman_swp_interrupt_read_status(struct qbman_swp *p); |
| @@ -158,9 +209,6 @@ void qbman_pull_desc_set_wq(struct qbman_pull_desc *d, u32 wqid, · 18 unmodified lines | |||
| 158 | void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, | 209 | void qbman_pull_desc_set_channel(struct qbman_pull_desc *d, u32 chid, |
| 159 | enum qbman_pull_type_e dct); | 210 | enum qbman_pull_type_e dct); |
| 160 | 211 | ||
| 161 | int qbman_swp_pull(struct qbman_swp *p, struct qbman_pull_desc *d); | ||
| 162 | |||
| 163 | const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s); | ||
| 164 | void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq); | 212 | void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct dpaa2_dq *dq); |
| 165 | 213 | ||
| 166 | int qbman_result_has_new_result(struct qbman_swp *p, const struct dpaa2_dq *dq); | 214 | int qbman_result_has_new_result(struct qbman_swp *p, const struct dpaa2_dq *dq); |
| @@ -172,15 +220,11 @@ void qbman_eq_desc_set_fq(struct qbman_eq_desc *d, u32 fqid); · 5 unmodified lines | |||
| 172 | void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, | 220 | void qbman_eq_desc_set_qd(struct qbman_eq_desc *d, u32 qdid, |
| 173 | u32 qd_bin, u32 qd_prio); | 221 | u32 qd_bin, u32 qd_prio); |
| 174 | 222 | ||
| 175 | int qbman_swp_enqueue(struct qbman_swp *p, const struct qbman_eq_desc *d, | ||
| 176 | const struct dpaa2_fd *fd); | ||
| 177 | 223 | ||
| 178 | void qbman_release_desc_clear(struct qbman_release_desc *d); | 224 | void qbman_release_desc_clear(struct qbman_release_desc *d); |
| 179 | void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid); | 225 | void qbman_release_desc_set_bpid(struct qbman_release_desc *d, u16 bpid); |
| 180 | void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable); | 226 | void qbman_release_desc_set_rcdi(struct qbman_release_desc *d, int enable); |
| 181 | 227 | ||
| 182 | int qbman_swp_release(struct qbman_swp *s, const struct qbman_release_desc *d, | ||
| 183 | const u64 *buffers, unsigned int num_buffers); | ||
| 184 | int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, | 228 | int qbman_swp_acquire(struct qbman_swp *s, u16 bpid, u64 *buffers, |
| 185 | unsigned int num_buffers); | 229 | unsigned int num_buffers); |
| 186 | int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, | 230 | int qbman_swp_alt_fq_state(struct qbman_swp *s, u32 fqid, |
| @@ -193,6 +237,61 @@ void *qbman_swp_mc_start(struct qbman_swp *p); · 6 unmodified lines | |||
| 193 | void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb); | 237 | void qbman_swp_mc_submit(struct qbman_swp *p, void *cmd, u8 cmd_verb); |
| 194 | void *qbman_swp_mc_result(struct qbman_swp *p); | 238 | void *qbman_swp_mc_result(struct qbman_swp *p); |
| 195 | 239 | ||
| 240 | /** | ||
| 241 | * qbman_swp_enqueue() - Issue an enqueue command | ||
| 242 | * @s: the software portal used for enqueue | ||
| 243 | * @d: the enqueue descriptor | ||
| 244 | * @fd: the frame descriptor to be enqueued | ||
| 245 | * | ||
| 246 | * Return 0 for successful enqueue, -EBUSY if the EQCR is not ready. | ||
| 247 | */ | ||
| 248 | static inline int | ||
| 249 | qbman_swp_enqueue(struct qbman_swp *s, const struct qbman_eq_desc *d, | ||
| 250 | const struct dpaa2_fd *fd) | ||
| 251 | { | ||
| 252 | return qbman_swp_enqueue_ptr(s, d, fd); | ||
| 253 | } | ||
| 254 | |||
| 255 | /** | ||
| 256 | * qbman_swp_enqueue_multiple() - Issue a multi enqueue command | ||
| 257 | * using one enqueue descriptor | ||
| 258 | * @s: the software portal used for enqueue | ||
| 259 | * @d: the enqueue descriptor | ||
| 260 | * @fd: table pointer of frame descriptor table to be enqueued | ||
| 261 | * @flags: table pointer of QBMAN_ENQUEUE_FLAG_DCA flags, not used if NULL | ||
| 262 | * @num_frames: number of fd to be enqueued | ||
| 263 | * | ||
| 264 | * Return the number of fd enqueued, or a negative error number. | ||
| 265 | */ | ||
| 266 | static inline int | ||
| 267 | qbman_swp_enqueue_multiple(struct qbman_swp *s, | ||
| 268 | const struct qbman_eq_desc *d, | ||
| 269 | const struct dpaa2_fd *fd, | ||
| 270 | uint32_t *flags, | ||
| 271 | int num_frames) | ||
| 272 | { | ||
| 273 | return qbman_swp_enqueue_multiple_ptr(s, d, fd, flags, num_frames); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * qbman_swp_enqueue_multiple_desc() - Issue a multi enqueue command | ||
| 278 | * using multiple enqueue descriptor | ||
| 279 | * @s: the software portal used for enqueue | ||
| 280 | * @d: table of minimal enqueue descriptor | ||
| 281 | * @fd: table pointer of frame descriptor table to be enqueued | ||
| 282 | * @num_frames: number of fd to be enqueued | ||
| 283 | * | ||
| 284 | * Return the number of fd enqueued, or a negative error number. | ||
| 285 | */ | ||
| 286 | static inline int | ||
| 287 | qbman_swp_enqueue_multiple_desc(struct qbman_swp *s, | ||
| 288 | const struct qbman_eq_desc *d, | ||
| 289 | const struct dpaa2_fd *fd, | ||
| 290 | int num_frames) | ||
| 291 | { | ||
| 292 | return qbman_swp_enqueue_multiple_desc_ptr(s, d, fd, num_frames); | ||
| 293 | } | ||
| 294 | |||
| 196 | /** | 295 | /** |
| 197 | * qbman_result_is_DQ() - check if the dequeue result is a dequeue response | 296 | * qbman_result_is_DQ() - check if the dequeue result is a dequeue response |
| 198 | * @dq: the dequeue result to be checked | 297 | * @dq: the dequeue result to be checked |
| @@ -504,4 +603,49 @@ int qbman_bp_query(struct qbman_swp *s, u16 bpid, · 305 unmodified lines | |||
| 504 | 603 | ||
| 505 | u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a); | 604 | u32 qbman_bp_info_num_free_bufs(struct qbman_bp_query_rslt *a); |
| 506 | 605 | ||
| 606 | /** | ||
| 607 | * qbman_swp_release() - Issue a buffer release command | ||
| 608 | * @s: the software portal object | ||
| 609 | * @d: the release descriptor | ||
| 610 | * @buffers: a pointer pointing to the buffer address to be released | ||
| 611 | * @num_buffers: number of buffers to be released, must be less than 8 | ||
| 612 | * | ||
| 613 | * Return 0 for success, -EBUSY if the release command ring is not ready. | ||
| 614 | */ | ||
| 615 | static inline int qbman_swp_release(struct qbman_swp *s, | ||
| 616 | const struct qbman_release_desc *d, | ||
| 617 | const u64 *buffers, | ||
| 618 | unsigned int num_buffers) | ||
| 619 | { | ||
| 620 | return qbman_swp_release_ptr(s, d, buffers, num_buffers); | ||
| 621 | } | ||
| 622 | |||
| 623 | /** | ||
| 624 | * qbman_swp_pull() - Issue the pull dequeue command | ||
| 625 | * @s: the software portal object | ||
| 626 | * @d: the software portal descriptor which has been configured with | ||
| 627 | * the set of qbman_pull_desc_set_*() calls | ||
| 628 | * | ||
| 629 | * Return 0 for success, and -EBUSY if the software portal is not ready | ||
| 630 | * to do pull dequeue. | ||
| 631 | */ | ||
| 632 | static inline int qbman_swp_pull(struct qbman_swp *s, | ||
| 633 | struct qbman_pull_desc *d) | ||
| 634 | { | ||
| 635 | return qbman_swp_pull_ptr(s, d); | ||
| 636 | } | ||
| 637 | |||
| 638 | /** | ||
| 639 | * qbman_swp_dqrr_next() - Get an valid DQRR entry | ||
| 640 | * @s: the software portal object | ||
| 641 | * | ||
| 642 | * Return NULL if there are no unconsumed DQRR entries. Return a DQRR entry | ||
| 643 | * only once, so repeated calls can return a sequence of DQRR entries, without | ||
| 644 | * requiring they be consumed immediately or in any particular order. | ||
| 645 | */ | ||
| 646 | static inline const struct dpaa2_dq *qbman_swp_dqrr_next(struct qbman_swp *s) | ||
| 647 | { | ||
| 648 | return qbman_swp_dqrr_next_ptr(s); | ||
| 649 | } | ||
| 650 | |||
| 507 | #endif /* __FSL_QBMAN_PORTAL_H */ | 651 | #endif /* __FSL_QBMAN_PORTAL_H */ |
| @@ -423,7 +423,7 @@ static void qe_upload_microcode(const void *base, · 422 unmodified lines | |||
| 423 | qe_iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); | 423 | qe_iowrite32be(be32_to_cpu(code[i]), &qe_immr->iram.idata); |
| 424 | 424 | ||
| 425 | /* Set I-RAM Ready Register */ | 425 | /* Set I-RAM Ready Register */ |
| 426 | qe_iowrite32be(be32_to_cpu(QE_IRAM_READY), &qe_immr->iram.iready); | 426 | qe_iowrite32be(QE_IRAM_READY, &qe_immr->iram.iready); |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | /* | 429 | /* |
| @@ -525,7 +525,7 @@ int qe_upload_firmware(const struct qe_firmware *firmware) · 95 unmodified lines | |||
| 525 | */ | 525 | */ |
| 526 | memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); | 526 | memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); |
| 527 | strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); | 527 | strlcpy(qe_firmware_info.id, firmware->id, sizeof(qe_firmware_info.id)); |
| 528 | qe_firmware_info.extended_modes = firmware->extended_modes; | 528 | qe_firmware_info.extended_modes = be64_to_cpu(firmware->extended_modes); |
| 529 | memcpy(qe_firmware_info.vtraps, firmware->vtraps, | 529 | memcpy(qe_firmware_info.vtraps, firmware->vtraps, |
| 530 | sizeof(firmware->vtraps)); | 530 | sizeof(firmware->vtraps)); |
| 531 | 531 | ||
| @@ -46,7 +46,7 @@ int cpm_muram_init(void) · 45 unmodified lines | |||
| 46 | { | 46 | { |
| 47 | struct device_node *np; | 47 | struct device_node *np; |
| 48 | struct resource r; | 48 | struct resource r; |
| 49 | u32 zero[OF_MAX_ADDR_CELLS] = {}; | 49 | __be32 zero[OF_MAX_ADDR_CELLS] = {}; |
| 50 | resource_size_t max = 0; | 50 | resource_size_t max = 0; |
| 51 | int i = 0; | 51 | int i = 0; |
| 52 | int ret = 0; | 52 | int ret = 0; |
| @@ -44,7 +44,7 @@ · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | struct qe_ic { | 45 | struct qe_ic { |
| 46 | /* Control registers offset */ | 46 | /* Control registers offset */ |
| 47 | u32 __iomem *regs; | 47 | __be32 __iomem *regs; |
| 48 | 48 | ||
| 49 | /* The remapper for this QEIC */ | 49 | /* The remapper for this QEIC */ |
| 50 | struct irq_domain *irqhost; | 50 | struct irq_domain *irqhost; |
| @@ -632,7 +632,7 @@ int ucc_set_tdm_rxtx_sync(u32 tdm_num, enum qe_clock clock, · 631 unmodified lines | |||
| 632 | { | 632 | { |
| 633 | int source; | 633 | int source; |
| 634 | u32 shift; | 634 | u32 shift; |
| 635 | struct qe_mux *qe_mux_reg; | 635 | struct qe_mux __iomem *qe_mux_reg; |
| 636 | 636 | ||
| 637 | qe_mux_reg = &qe_immr->qmx; | 637 | qe_mux_reg = &qe_immr->qmx; |
| 638 | 638 | ||
| @@ -72,7 +72,7 @@ EXPORT_SYMBOL(ucc_slow_restart_tx); · 71 unmodified lines | |||
| 72 | 72 | ||
| 73 | void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) | 73 | void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) |
| 74 | { | 74 | { |
| 75 | struct ucc_slow *us_regs; | 75 | struct ucc_slow __iomem *us_regs; |
| 76 | u32 gumr_l; | 76 | u32 gumr_l; |
| 77 | 77 | ||
| 78 | us_regs = uccs->us_regs; | 78 | us_regs = uccs->us_regs; |
| @@ -93,7 +93,7 @@ EXPORT_SYMBOL(ucc_slow_enable); · 14 unmodified lines | |||
| 93 | 93 | ||
| 94 | void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) | 94 | void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) |
| 95 | { | 95 | { |
| 96 | struct ucc_slow *us_regs; | 96 | struct ucc_slow __iomem *us_regs; |
| 97 | u32 gumr_l; | 97 | u32 gumr_l; |
| 98 | 98 | ||
| 99 | us_regs = uccs->us_regs; | 99 | us_regs = uccs->us_regs; |
| @@ -122,7 +122,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc · 22 unmodified lines | |||
| 122 | u32 i; | 122 | u32 i; |
| 123 | struct ucc_slow __iomem *us_regs; | 123 | struct ucc_slow __iomem *us_regs; |
| 124 | u32 gumr; | 124 | u32 gumr; |
| 125 | struct qe_bd *bd; | 125 | struct qe_bd __iomem *bd; |
| 126 | u32 id; | 126 | u32 id; |
| 127 | u32 command; | 127 | u32 command; |
| 128 | int ret = 0; | 128 | int ret = 0; |
| @@ -168,16 +168,9 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc · 39 unmodified lines | |||
| 168 | return -ENOMEM; | 168 | return -ENOMEM; |
| 169 | } | 169 | } |
| 170 | 170 | ||
| 171 | uccs->saved_uccm = 0; | ||
| 172 | uccs->p_rx_frame = 0; | ||
| 173 | us_regs = uccs->us_regs; | 171 | us_regs = uccs->us_regs; |
| 174 | uccs->p_ucce = (u16 *) & (us_regs->ucce); | 172 | uccs->p_ucce = &us_regs->ucce; |
| 175 | uccs->p_uccm = (u16 *) & (us_regs->uccm); | 173 | uccs->p_uccm = &us_regs->uccm; |
| 176 | #ifdef STATISTICS | ||
| 177 | uccs->rx_frames = 0; | ||
| 178 | uccs->tx_frames = 0; | ||
| 179 | uccs->rx_discarded = 0; | ||
| 180 | #endif /* STATISTICS */ | ||
| 181 | 174 | ||
| 182 | /* Get PRAM base */ | 175 | /* Get PRAM base */ |
| 183 | uccs->us_pram_offset = | 176 | uccs->us_pram_offset = |
| @@ -231,24 +224,24 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc · 47 unmodified lines | |||
| 231 | /* clear bd buffer */ | 224 | /* clear bd buffer */ |
| 232 | qe_iowrite32be(0, &bd->buf); | 225 | qe_iowrite32be(0, &bd->buf); |
| 233 | /* set bd status and length */ | 226 | /* set bd status and length */ |
| 234 | qe_iowrite32be(0, (u32 *)bd); | 227 | qe_iowrite32be(0, (u32 __iomem *)bd); |
| 235 | bd++; | 228 | bd++; |
| 236 | } | 229 | } |
| 237 | /* for last BD set Wrap bit */ | 230 | /* for last BD set Wrap bit */ |
| 238 | qe_iowrite32be(0, &bd->buf); | 231 | qe_iowrite32be(0, &bd->buf); |
| 239 | qe_iowrite32be(cpu_to_be32(T_W), (u32 *)bd); | 232 | qe_iowrite32be(T_W, (u32 __iomem *)bd); |
| 240 | 233 | ||
| 241 | /* Init Rx bds */ | 234 | /* Init Rx bds */ |
| 242 | bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); | 235 | bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); |
| 243 | for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) { | 236 | for (i = 0; i < us_info->rx_bd_ring_len - 1; i++) { |
| 244 | /* set bd status and length */ | 237 | /* set bd status and length */ |
| 245 | qe_iowrite32be(0, (u32 *)bd); | 238 | qe_iowrite32be(0, (u32 __iomem *)bd); |
| 246 | /* clear bd buffer */ | 239 | /* clear bd buffer */ |
| 247 | qe_iowrite32be(0, &bd->buf); | 240 | qe_iowrite32be(0, &bd->buf); |
| 248 | bd++; | 241 | bd++; |
| 249 | } | 242 | } |
| 250 | /* for last BD set Wrap bit */ | 243 | /* for last BD set Wrap bit */ |
| 251 | qe_iowrite32be(cpu_to_be32(R_W), (u32 *)bd); | 244 | qe_iowrite32be(R_W, (u32 __iomem *)bd); |
| 252 | qe_iowrite32be(0, &bd->buf); | 245 | qe_iowrite32be(0, &bd->buf); |
| 253 | 246 | ||
| 254 | /* Set GUMR (For more details see the hardware spec.). */ | 247 | /* Set GUMR (For more details see the hardware spec.). */ |
| @@ -273,8 +266,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc · 18 unmodified lines | |||
| 273 | qe_iowrite32be(gumr, &us_regs->gumr_h); | 266 | qe_iowrite32be(gumr, &us_regs->gumr_h); |
| 274 | 267 | ||
| 275 | /* gumr_l */ | 268 | /* gumr_l */ |
| 276 | gumr = us_info->tdcr | us_info->rdcr | us_info->tenc | us_info->renc | | 269 | gumr = (u32)us_info->tdcr | (u32)us_info->rdcr | (u32)us_info->tenc | |
| 277 | us_info->diag | us_info->mode; | 270 | (u32)us_info->renc | (u32)us_info->diag | (u32)us_info->mode; |
| 278 | if (us_info->tci) | 271 | if (us_info->tci) |
| 279 | gumr |= UCC_SLOW_GUMR_L_TCI; | 272 | gumr |= UCC_SLOW_GUMR_L_TCI; |
| 280 | if (us_info->rinv) | 273 | if (us_info->rinv) |
| @@ -289,8 +282,8 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc · 8 unmodified lines | |||
| 289 | 282 | ||
| 290 | /* if the data is in cachable memory, the 'global' */ | 283 | /* if the data is in cachable memory, the 'global' */ |
| 291 | /* in the function code should be set. */ | 284 | /* in the function code should be set. */ |
| 292 | uccs->us_pram->tbmr = UCC_BMR_BO_BE; | 285 | qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->tbmr); |
| 293 | uccs->us_pram->rbmr = UCC_BMR_BO_BE; | 286 | qe_iowrite8(UCC_BMR_BO_BE, &uccs->us_pram->rbmr); |
| 294 | 287 | ||
| 295 | /* rbase, tbase are offsets from MURAM base */ | 288 | /* rbase, tbase are offsets from MURAM base */ |
| 296 | qe_iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase); | 289 | qe_iowrite16be(uccs->rx_base_offset, &uccs->us_pram->rbase); |
| @@ -10,11 +10,20 @@ config IMX_GPCV2_PM_DOMAINS · 9 unmodified lines | |||
| 10 | 10 | ||
| 11 | config IMX_SCU_SOC | 11 | config IMX_SCU_SOC |
| 12 | bool "i.MX System Controller Unit SoC info support" | 12 | bool "i.MX System Controller Unit SoC info support" |
| 13 | depends on IMX_SCU || COMPILE_TEST | 13 | depends on IMX_SCU |
| 14 | select SOC_BUS | 14 | select SOC_BUS |
| 15 | help | 15 | help |
| 16 | If you say yes here you get support for the NXP i.MX System | 16 | If you say yes here you get support for the NXP i.MX System |
| 17 | Controller Unit SoC info module, it will provide the SoC info | 17 | Controller Unit SoC info module, it will provide the SoC info |
| 18 | like SoC family, ID and revision etc. | 18 | like SoC family, ID and revision etc. |
| 19 | 19 | ||
| 20 | config SOC_IMX8M | ||
| 21 | bool "i.MX8M SoC family support" | ||
| 22 | depends on ARCH_MXC || COMPILE_TEST | ||
| 23 | default ARCH_MXC && ARM64 | ||
| 24 | help | ||
| 25 | If you say yes here you get support for the NXP i.MX8M family | ||
| 26 | support, it will provide the SoC info like SoC family, | ||
| 27 | ID and revision etc. | ||
| 28 | |||
| 20 | endmenu | 29 | endmenu |
| @@ -1,5 +1,5 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o | 2 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o |
| 3 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o | 3 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o |
| 4 | obj-$(CONFIG_ARCH_MXC) += soc-imx8.o | 4 | obj-$(CONFIG_SOC_IMX8M) += soc-imx8m.o |
| 5 | obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o | 5 | obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o |
| @@ -87,8 +87,8 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) · 86 unmodified lines | |||
| 87 | static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) | 87 | static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) |
| 88 | { | 88 | { |
| 89 | struct imx_pm_domain *pd = to_imx_pm_domain(genpd); | 89 | struct imx_pm_domain *pd = to_imx_pm_domain(genpd); |
| 90 | int i, ret, sw, sw2iso; | 90 | int i, ret; |
| 91 | u32 val; | 91 | u32 val, req; |
| 92 | 92 | ||
| 93 | if (pd->supply) { | 93 | if (pd->supply) { |
| 94 | ret = regulator_enable(pd->supply); | 94 | ret = regulator_enable(pd->supply); |
| @@ -107,17 +107,18 @@ static int imx6_pm_domain_power_on(struct generic_pm_domain *genpd) · 12 unmodified lines | |||
| 107 | regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, | 107 | regmap_update_bits(pd->regmap, pd->reg_offs + GPC_PGC_CTRL_OFFS, |
| 108 | 0x1, 0x1); | 108 | 0x1, 0x1); |
| 109 | 109 | ||
| 110 | /* Read ISO and ISO2SW power up delays */ | ||
| 111 | regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); | ||
| 112 | sw = val & 0x3f; | ||
| 113 | sw2iso = (val >> 8) & 0x3f; | ||
| 114 | |||
| 115 | /* Request GPC to power up domain */ | 110 | /* Request GPC to power up domain */ |
| 116 | val = BIT(pd->cntr_pdn_bit + 1); | 111 | req = BIT(pd->cntr_pdn_bit + 1); |
| 117 | regmap_update_bits(pd->regmap, GPC_CNTR, val, val); | 112 | regmap_update_bits(pd->regmap, GPC_CNTR, req, req); |
| 118 | 113 | ||
| 119 | /* Wait ISO + ISO2SW IPG clock cycles */ | 114 | /* Wait for the PGC to handle the request */ |
| 120 | udelay(DIV_ROUND_UP(sw + sw2iso, pd->ipg_rate_mhz)); | 115 | ret = regmap_read_poll_timeout(pd->regmap, GPC_CNTR, val, !(val & req), |
| 116 | 1, 50); | ||
| 117 | if (ret) | ||
| 118 | pr_err("powerup request on domain %s timed out\n", genpd->name); | ||
| 119 | |||
| 120 | /* Wait for reset to propagate through peripherals */ | ||
| 121 | usleep_range(5, 10); | ||
| 121 | 122 | ||
| 122 | /* Disable reset clocks for all devices in the domain */ | 123 | /* Disable reset clocks for all devices in the domain */ |
| 123 | for (i = 0; i < pd->num_clks; i++) | 124 | for (i = 0; i < pd->num_clks; i++) |
| @@ -343,6 +344,7 @@ static const struct regmap_config imx_gpc_regmap_config = { · 219 unmodified lines | |||
| 343 | .rd_table = &access_table, | 344 | .rd_table = &access_table, |
| 344 | .wr_table = &access_table, | 345 | .wr_table = &access_table, |
| 345 | .max_register = 0x2ac, | 346 | .max_register = 0x2ac, |
| 347 | .fast_io = true, | ||
| 346 | }; | 348 | }; |
| 347 | 349 | ||
| 348 | static struct generic_pm_domain *imx_gpc_onecell_domains[] = { | 350 | static struct generic_pm_domain *imx_gpc_onecell_domains[] = { |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/pm_domain.h> | 14 | #include <linux/pm_domain.h> |
| 15 | #include <linux/regmap.h> | 15 | #include <linux/regmap.h> |
| 16 | #include <linux/regulator/consumer.h> | 16 | #include <linux/regulator/consumer.h> |
| 17 | #include <linux/sizes.h> | ||
| 17 | #include <dt-bindings/power/imx7-power.h> | 18 | #include <dt-bindings/power/imx7-power.h> |
| 18 | #include <dt-bindings/power/imx8mq-power.h> | 19 | #include <dt-bindings/power/imx8mq-power.h> |
| 19 | 20 | ||
File renamed without changes.
| @@ -76,6 +76,10 @@ config QCOM_OCMEM · 75 unmodified lines | |||
| 76 | requirements. This is typically used by the GPU, camera/video, and | 76 | requirements. This is typically used by the GPU, camera/video, and |
| 77 | audio components on some Snapdragon SoCs. | 77 | audio components on some Snapdragon SoCs. |
| 78 | 78 | ||
| 79 | config QCOM_PDR_HELPERS | ||
| 80 | tristate | ||
| 81 | select QCOM_QMI_HELPERS | ||
| 82 | |||
| 79 | config QCOM_PM | 83 | config QCOM_PM |
| 80 | bool "Qualcomm Power Management" | 84 | bool "Qualcomm Power Management" |
| 81 | depends on ARCH_QCOM && !ARM64 | 85 | depends on ARCH_QCOM && !ARM64 |
| @@ -88,7 +92,6 @@ config QCOM_PM · 6 unmodified lines | |||
| 88 | 92 | ||
| 89 | config QCOM_QMI_HELPERS | 93 | config QCOM_QMI_HELPERS |
| 90 | tristate | 94 | tristate |
| 91 | depends on ARCH_QCOM || COMPILE_TEST | ||
| 92 | depends on NET | 95 | depends on NET |
| 93 | 96 | ||
| 94 | config QCOM_RMTFS_MEM | 97 | config QCOM_RMTFS_MEM |
| @@ -197,6 +200,8 @@ config QCOM_APR · 102 unmodified lines | |||
| 197 | tristate "Qualcomm APR Bus (Asynchronous Packet Router)" | 200 | tristate "Qualcomm APR Bus (Asynchronous Packet Router)" |
| 198 | depends on ARCH_QCOM || COMPILE_TEST | 201 | depends on ARCH_QCOM || COMPILE_TEST |
| 199 | depends on RPMSG | 202 | depends on RPMSG |
| 203 | depends on NET | ||
| 204 | select QCOM_PDR_HELPERS | ||
| 200 | help | 205 | help |
| 201 | Enable APR IPC protocol support between | 206 | Enable APR IPC protocol support between |
| 202 | application processor and QDSP6. APR is | 207 | application processor and QDSP6. APR is |
| @@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o · 6 unmodified lines | |||
| 7 | obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o | 7 | obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o |
| 8 | obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o | 8 | obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o |
| 9 | obj-$(CONFIG_QCOM_OCMEM) += ocmem.o | 9 | obj-$(CONFIG_QCOM_OCMEM) += ocmem.o |
| 10 | obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o | ||
| 10 | obj-$(CONFIG_QCOM_PM) += spm.o | 11 | obj-$(CONFIG_QCOM_PM) += spm.o |
| 11 | obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o | 12 | obj-$(CONFIG_QCOM_QMI_HELPERS) += qmi_helpers.o |
| 12 | qmi_helpers-y += qmi_encdec.o qmi_interface.o | 13 | qmi_helpers-y += qmi_encdec.o qmi_interface.o |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <linux/workqueue.h> | 11 | #include <linux/workqueue.h> |
| 12 | #include <linux/of_device.h> | 12 | #include <linux/of_device.h> |
| 13 | #include <linux/soc/qcom/apr.h> | 13 | #include <linux/soc/qcom/apr.h> |
| 14 | #include <linux/soc/qcom/pdr.h> | ||
| 14 | #include <linux/rpmsg.h> | 15 | #include <linux/rpmsg.h> |
| 15 | #include <linux/of.h> | 16 | #include <linux/of.h> |
| 16 | 17 | ||
| @@ -21,6 +22,7 @@ struct apr { · 4 unmodified lines | |||
| 21 | spinlock_t rx_lock; | 22 | spinlock_t rx_lock; |
| 22 | struct idr svcs_idr; | 23 | struct idr svcs_idr; |
| 23 | int dest_domain_id; | 24 | int dest_domain_id; |
| 25 | struct pdr_handle *pdr; | ||
| 24 | struct workqueue_struct *rxwq; | 26 | struct workqueue_struct *rxwq; |
| 25 | struct work_struct rx_work; | 27 | struct work_struct rx_work; |
| 26 | struct list_head rx_list; | 28 | struct list_head rx_list; |
| @@ -289,6 +291,9 @@ static int apr_add_device(struct device *dev, struct device_node *np, · 262 unmodified lines | |||
| 289 | id->svc_id + 1, GFP_ATOMIC); | 291 | id->svc_id + 1, GFP_ATOMIC); |
| 290 | spin_unlock(&apr->svcs_lock); | 292 | spin_unlock(&apr->svcs_lock); |
| 291 | 293 | ||
| 294 | of_property_read_string_index(np, "qcom,protection-domain", | ||
| 295 | 1, &adev->service_path); | ||
| 296 | |||
| 292 | dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev)); | 297 | dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev)); |
| 293 | 298 | ||
| 294 | ret = device_register(&adev->dev); | 299 | ret = device_register(&adev->dev); |
| @@ -300,14 +305,75 @@ static int apr_add_device(struct device *dev, struct device_node *np, · 5 unmodified lines | |||
| 300 | return ret; | 305 | return ret; |
| 301 | } | 306 | } |
| 302 | 307 | ||
| 303 | static void of_register_apr_devices(struct device *dev) | 308 | static int of_apr_add_pd_lookups(struct device *dev) |
| 309 | { | ||
| 310 | const char *service_name, *service_path; | ||
| 311 | struct apr *apr = dev_get_drvdata(dev); | ||
| 312 | struct device_node *node; | ||
| 313 | struct pdr_service *pds; | ||
| 314 | int ret; | ||
| 315 | |||
| 316 | for_each_child_of_node(dev->of_node, node) { | ||
| 317 | ret = of_property_read_string_index(node, "qcom,protection-domain", | ||
| 318 | 0, &service_name); | ||
| 319 | if (ret < 0) | ||
| 320 | continue; | ||
| 321 | |||
| 322 | ret = of_property_read_string_index(node, "qcom,protection-domain", | ||
| 323 | 1, &service_path); | ||
| 324 | if (ret < 0) { | ||
| 325 | dev_err(dev, "pdr service path missing: %d\n", ret); | ||
| 326 | return ret; | ||
| 327 | } | ||
| 328 | |||
| 329 | pds = pdr_add_lookup(apr->pdr, service_name, service_path); | ||
| 330 | if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { | ||
| 331 | dev_err(dev, "pdr add lookup failed: %d\n", ret); | ||
| 332 | return PTR_ERR(pds); | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | static void of_register_apr_devices(struct device *dev, const char *svc_path) | ||
| 304 | { | 340 | { |
| 305 | struct apr *apr = dev_get_drvdata(dev); | 341 | struct apr *apr = dev_get_drvdata(dev); |
| 306 | struct device_node *node; | 342 | struct device_node *node; |
| 343 | const char *service_path; | ||
| 344 | int ret; | ||
| 307 | 345 | ||
| 308 | for_each_child_of_node(dev->of_node, node) { | 346 | for_each_child_of_node(dev->of_node, node) { |
| 309 | struct apr_device_id id = { {0} }; | 347 | struct apr_device_id id = { {0} }; |
| 310 | 348 | ||
| 349 | /* | ||
| 350 | * This function is called with svc_path NULL during | ||
| 351 | * apr_probe(), in which case we register any apr devices | ||
| 352 | * without a qcom,protection-domain specified. | ||
| 353 | * | ||
| 354 | * Then as the protection domains becomes available | ||
| 355 | * (if applicable) this function is again called, but with | ||
| 356 | * svc_path representing the service becoming available. In | ||
| 357 | * this case we register any apr devices with a matching | ||
| 358 | * qcom,protection-domain. | ||
| 359 | */ | ||
| 360 | |||
| 361 | ret = of_property_read_string_index(node, "qcom,protection-domain", | ||
| 362 | 1, &service_path); | ||
| 363 | if (svc_path) { | ||
| 364 | /* skip APR services that are PD independent */ | ||
| 365 | if (ret) | ||
| 366 | continue; | ||
| 367 | |||
| 368 | /* skip APR services whose PD paths don't match */ | ||
| 369 | if (strcmp(service_path, svc_path)) | ||
| 370 | continue; | ||
| 371 | } else { | ||
| 372 | /* skip APR services whose PD lookups are registered */ | ||
| 373 | if (ret == 0) | ||
| 374 | continue; | ||
| 375 | } | ||
| 376 | |||
| 311 | if (of_property_read_u32(node, "reg", &id.svc_id)) | 377 | if (of_property_read_u32(node, "reg", &id.svc_id)) |
| 312 | continue; | 378 | continue; |
| 313 | 379 | ||
| @@ -318,6 +384,34 @@ static void of_register_apr_devices(struct device *dev) · 4 unmodified lines | |||
| 318 | } | 384 | } |
| 319 | } | 385 | } |
| 320 | 386 | ||
| 387 | static int apr_remove_device(struct device *dev, void *svc_path) | ||
| 388 | { | ||
| 389 | struct apr_device *adev = to_apr_device(dev); | ||
| 390 | |||
| 391 | if (svc_path && adev->service_path) { | ||
| 392 | if (!strcmp(adev->service_path, (char *)svc_path)) | ||
| 393 | device_unregister(&adev->dev); | ||
| 394 | } else { | ||
| 395 | device_unregister(&adev->dev); | ||
| 396 | } | ||
| 397 | |||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | |||
| 401 | static void apr_pd_status(int state, char *svc_path, void *priv) | ||
| 402 | { | ||
| 403 | struct apr *apr = (struct apr *)priv; | ||
| 404 | |||
| 405 | switch (state) { | ||
| 406 | case SERVREG_SERVICE_STATE_UP: | ||
| 407 | of_register_apr_devices(apr->dev, svc_path); | ||
| 408 | break; | ||
| 409 | case SERVREG_SERVICE_STATE_DOWN: | ||
| 410 | device_for_each_child(apr->dev, svc_path, apr_remove_device); | ||
| 411 | break; | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 321 | static int apr_probe(struct rpmsg_device *rpdev) | 415 | static int apr_probe(struct rpmsg_device *rpdev) |
| 322 | { | 416 | { |
| 323 | struct device *dev = &rpdev->dev; | 417 | struct device *dev = &rpdev->dev; |
| @@ -343,28 +437,39 @@ static int apr_probe(struct rpmsg_device *rpdev) · 19 unmodified lines | |||
| 343 | return -ENOMEM; | 437 | return -ENOMEM; |
| 344 | } | 438 | } |
| 345 | INIT_WORK(&apr->rx_work, apr_rxwq); | 439 | INIT_WORK(&apr->rx_work, apr_rxwq); |
| 440 | |||
| 441 | apr->pdr = pdr_handle_alloc(apr_pd_status, apr); | ||
| 442 | if (IS_ERR(apr->pdr)) { | ||
| 443 | dev_err(dev, "Failed to init PDR handle\n"); | ||
| 444 | ret = PTR_ERR(apr->pdr); | ||
| 445 | goto destroy_wq; | ||
| 446 | } | ||
| 447 | |||
| 346 | INIT_LIST_HEAD(&apr->rx_list); | 448 | INIT_LIST_HEAD(&apr->rx_list); |
| 347 | spin_lock_init(&apr->rx_lock); | 449 | spin_lock_init(&apr->rx_lock); |
| 348 | spin_lock_init(&apr->svcs_lock); | 450 | spin_lock_init(&apr->svcs_lock); |
| 349 | idr_init(&apr->svcs_idr); | 451 | idr_init(&apr->svcs_idr); |
| 350 | of_register_apr_devices(dev); | ||
| 351 | |||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | 452 | ||
| 355 | static int apr_remove_device(struct device *dev, void *null) | 453 | ret = of_apr_add_pd_lookups(dev); |
| 356 | { | 454 | if (ret) |
| 357 | struct apr_device *adev = to_apr_device(dev); | 455 | goto handle_release; |
| 358 | 456 | ||
| 359 | device_unregister(&adev->dev); | 457 | of_register_apr_devices(dev, NULL); |
| 360 | 458 | ||
| 361 | return 0; | 459 | return 0; |
| 460 | |||
| 461 | handle_release: | ||
| 462 | pdr_handle_release(apr->pdr); | ||
| 463 | destroy_wq: | ||
| 464 | destroy_workqueue(apr->rxwq); | ||
| 465 | return ret; | ||
| 362 | } | 466 | } |
| 363 | 467 | ||
| 364 | static void apr_remove(struct rpmsg_device *rpdev) | 468 | static void apr_remove(struct rpmsg_device *rpdev) |
| 365 | { | 469 | { |
| 366 | struct apr *apr = dev_get_drvdata(&rpdev->dev); | 470 | struct apr *apr = dev_get_drvdata(&rpdev->dev); |
| 367 | 471 | ||
| 472 | pdr_handle_release(apr->pdr); | ||
| 368 | device_for_each_child(&rpdev->dev, NULL, apr_remove_device); | 473 | device_for_each_child(&rpdev->dev, NULL, apr_remove_device); |
| 369 | flush_workqueue(apr->rxwq); | 474 | flush_workqueue(apr->rxwq); |
| 370 | destroy_workqueue(apr->rxwq); | 475 | destroy_workqueue(apr->rxwq); |
| @@ -0,0 +1,757 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2020 The Linux Foundation. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kernel.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/string.h> | ||
| 9 | #include <linux/workqueue.h> | ||
| 10 | |||
| 11 | #include "pdr_internal.h" | ||
| 12 | |||
| 13 | struct pdr_service { | ||
| 14 | char service_name[SERVREG_NAME_LENGTH + 1]; | ||
| 15 | char service_path[SERVREG_NAME_LENGTH + 1]; | ||
| 16 | |||
| 17 | struct sockaddr_qrtr addr; | ||
| 18 | |||
| 19 | unsigned int instance; | ||
| 20 | unsigned int service; | ||
| 21 | u8 service_data_valid; | ||
| 22 | u32 service_data; | ||
| 23 | int state; | ||
| 24 | |||
| 25 | bool need_notifier_register; | ||
| 26 | bool need_notifier_remove; | ||
| 27 | bool need_locator_lookup; | ||
| 28 | bool service_connected; | ||
| 29 | |||
| 30 | struct list_head node; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct pdr_handle { | ||
| 34 | struct qmi_handle locator_hdl; | ||
| 35 | struct qmi_handle notifier_hdl; | ||
| 36 | |||
| 37 | struct sockaddr_qrtr locator_addr; | ||
| 38 | |||
| 39 | struct list_head lookups; | ||
| 40 | struct list_head indack_list; | ||
| 41 | |||
| 42 | /* control access to pdr lookup/indack lists */ | ||
| 43 | struct mutex list_lock; | ||
| 44 | |||
| 45 | /* serialize pd status invocation */ | ||
| 46 | struct mutex status_lock; | ||
| 47 | |||
| 48 | /* control access to the locator state */ | ||
| 49 | struct mutex lock; | ||
| 50 | |||
| 51 | bool locator_init_complete; | ||
| 52 | |||
| 53 | struct work_struct locator_work; | ||
| 54 | struct work_struct notifier_work; | ||
| 55 | struct work_struct indack_work; | ||
| 56 | |||
| 57 | struct workqueue_struct *notifier_wq; | ||
| 58 | struct workqueue_struct *indack_wq; | ||
| 59 | |||
| 60 | void (*status)(int state, char *service_path, void *priv); | ||
| 61 | void *priv; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct pdr_list_node { | ||
| 65 | enum servreg_service_state curr_state; | ||
| 66 | u16 transaction_id; | ||
| 67 | struct pdr_service *pds; | ||
| 68 | struct list_head node; | ||
| 69 | }; | ||
| 70 | |||
| 71 | static int pdr_locator_new_server(struct qmi_handle *qmi, | ||
| 72 | struct qmi_service *svc) | ||
| 73 | { | ||
| 74 | struct pdr_handle *pdr = container_of(qmi, struct pdr_handle, | ||
| 75 | locator_hdl); | ||
| 76 | struct pdr_service *pds; | ||
| 77 | |||
| 78 | /* Create a local client port for QMI communication */ | ||
| 79 | pdr->locator_addr.sq_family = AF_QIPCRTR; | ||
| 80 | pdr->locator_addr.sq_node = svc->node; | ||
| 81 | pdr->locator_addr.sq_port = svc->port; | ||
| 82 | |||
| 83 | mutex_lock(&pdr->lock); | ||
| 84 | pdr->locator_init_complete = true; | ||
| 85 | mutex_unlock(&pdr->lock); | ||
| 86 | |||
| 87 | /* Service pending lookup requests */ | ||
| 88 | mutex_lock(&pdr->list_lock); | ||
| 89 | list_for_each_entry(pds, &pdr->lookups, node) { | ||
| 90 | if (pds->need_locator_lookup) | ||
| 91 | schedule_work(&pdr->locator_work); | ||
| 92 | } | ||
| 93 | mutex_unlock(&pdr->list_lock); | ||
| 94 | |||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | |||
| 98 | static void pdr_locator_del_server(struct qmi_handle *qmi, | ||
| 99 | struct qmi_service *svc) | ||
| 100 | { | ||
| 101 | struct pdr_handle *pdr = container_of(qmi, struct pdr_handle, | ||
| 102 | locator_hdl); | ||
| 103 | |||
| 104 | mutex_lock(&pdr->lock); | ||
| 105 | pdr->locator_init_complete = false; | ||
| 106 | mutex_unlock(&pdr->lock); | ||
| 107 | |||
| 108 | pdr->locator_addr.sq_node = 0; | ||
| 109 | pdr->locator_addr.sq_port = 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | static struct qmi_ops pdr_locator_ops = { | ||
| 113 | .new_server = pdr_locator_new_server, | ||
| 114 | .del_server = pdr_locator_del_server, | ||
| 115 | }; | ||
| 116 | |||
| 117 | static int pdr_register_listener(struct pdr_handle *pdr, | ||
| 118 | struct pdr_service *pds, | ||
| 119 | bool enable) | ||
| 120 | { | ||
| 121 | struct servreg_register_listener_resp resp; | ||
| 122 | struct servreg_register_listener_req req; | ||
| 123 | struct qmi_txn txn; | ||
| 124 | int ret; | ||
| 125 | |||
| 126 | ret = qmi_txn_init(&pdr->notifier_hdl, &txn, | ||
| 127 | servreg_register_listener_resp_ei, | ||
| 128 | &resp); | ||
| 129 | if (ret < 0) | ||
| 130 | return ret; | ||
| 131 | |||
| 132 | req.enable = enable; | ||
| 133 | strcpy(req.service_path, pds->service_path); | ||
| 134 | |||
| 135 | ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, | ||
| 136 | &txn, SERVREG_REGISTER_LISTENER_REQ, | ||
| 137 | SERVREG_REGISTER_LISTENER_REQ_LEN, | ||
| 138 | servreg_register_listener_req_ei, | ||
| 139 | &req); | ||
| 140 | if (ret < 0) { | ||
| 141 | qmi_txn_cancel(&txn); | ||
| 142 | return ret; | ||
| 143 | } | ||
| 144 | |||
| 145 | ret = qmi_txn_wait(&txn, 5 * HZ); | ||
| 146 | if (ret < 0) { | ||
| 147 | pr_err("PDR: %s register listener txn wait failed: %d\n", | ||
| 148 | pds->service_path, ret); | ||
| 149 | return ret; | ||
| 150 | } | ||
| 151 | |||
| 152 | if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { | ||
| 153 | pr_err("PDR: %s register listener failed: 0x%x\n", | ||
| 154 | pds->service_path, resp.resp.error); | ||
| 155 | return ret; | ||
| 156 | } | ||
| 157 | |||
| 158 | if ((int)resp.curr_state < INT_MIN || (int)resp.curr_state > INT_MAX) | ||
| 159 | pr_err("PDR: %s notification state invalid: 0x%x\n", | ||
| 160 | pds->service_path, resp.curr_state); | ||
| 161 | |||
| 162 | pds->state = resp.curr_state; | ||
| 163 | |||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 167 | static void pdr_notifier_work(struct work_struct *work) | ||
| 168 | { | ||
| 169 | struct pdr_handle *pdr = container_of(work, struct pdr_handle, | ||
| 170 | notifier_work); | ||
| 171 | struct pdr_service *pds; | ||
| 172 | int ret; | ||
| 173 | |||
| 174 | mutex_lock(&pdr->list_lock); | ||
| 175 | list_for_each_entry(pds, &pdr->lookups, node) { | ||
| 176 | if (pds->service_connected) { | ||
| 177 | if (!pds->need_notifier_register) | ||
| 178 | continue; | ||
| 179 | |||
| 180 | pds->need_notifier_register = false; | ||
| 181 | ret = pdr_register_listener(pdr, pds, true); | ||
| 182 | if (ret < 0) | ||
| 183 | pds->state = SERVREG_SERVICE_STATE_DOWN; | ||
| 184 | } else { | ||
| 185 | if (!pds->need_notifier_remove) | ||
| 186 | continue; | ||
| 187 | |||
| 188 | pds->need_notifier_remove = false; | ||
| 189 | pds->state = SERVREG_SERVICE_STATE_DOWN; | ||
| 190 | } | ||
| 191 | |||
| 192 | mutex_lock(&pdr->status_lock); | ||
| 193 | pdr->status(pds->state, pds->service_path, pdr->priv); | ||
| 194 | mutex_unlock(&pdr->status_lock); | ||
| 195 | } | ||
| 196 | mutex_unlock(&pdr->list_lock); | ||
| 197 | } | ||
| 198 | |||
| 199 | static int pdr_notifier_new_server(struct qmi_handle *qmi, | ||
| 200 | struct qmi_service *svc) | ||
| 201 | { | ||
| 202 | struct pdr_handle *pdr = container_of(qmi, struct pdr_handle, | ||
| 203 | notifier_hdl); | ||
| 204 | struct pdr_service *pds; | ||
| 205 | |||
| 206 | mutex_lock(&pdr->list_lock); | ||
| 207 | list_for_each_entry(pds, &pdr->lookups, node) { | ||
| 208 | if (pds->service == svc->service && | ||
| 209 | pds->instance == svc->instance) { | ||
| 210 | pds->service_connected = true; | ||
| 211 | pds->need_notifier_register = true; | ||
| 212 | pds->addr.sq_family = AF_QIPCRTR; | ||
| 213 | pds->addr.sq_node = svc->node; | ||
| 214 | pds->addr.sq_port = svc->port; | ||
| 215 | queue_work(pdr->notifier_wq, &pdr->notifier_work); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | mutex_unlock(&pdr->list_lock); | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static void pdr_notifier_del_server(struct qmi_handle *qmi, | ||
| 224 | struct qmi_service *svc) | ||
| 225 | { | ||
| 226 | struct pdr_handle *pdr = container_of(qmi, struct pdr_handle, | ||
| 227 | notifier_hdl); | ||
| 228 | struct pdr_service *pds; | ||
| 229 | |||
| 230 | mutex_lock(&pdr->list_lock); | ||
| 231 | list_for_each_entry(pds, &pdr->lookups, node) { | ||
| 232 | if (pds->service == svc->service && | ||
| 233 | pds->instance == svc->instance) { | ||
| 234 | pds->service_connected = false; | ||
| 235 | pds->need_notifier_remove = true; | ||
| 236 | pds->addr.sq_node = 0; | ||
| 237 | pds->addr.sq_port = 0; | ||
| 238 | queue_work(pdr->notifier_wq, &pdr->notifier_work); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | mutex_unlock(&pdr->list_lock); | ||
| 242 | } | ||
| 243 | |||
| 244 | static struct qmi_ops pdr_notifier_ops = { | ||
| 245 | .new_server = pdr_notifier_new_server, | ||
| 246 | .del_server = pdr_notifier_del_server, | ||
| 247 | }; | ||
| 248 | |||
| 249 | static int pdr_send_indack_msg(struct pdr_handle *pdr, struct pdr_service *pds, | ||
| 250 | u16 tid) | ||
| 251 | { | ||
| 252 | struct servreg_set_ack_resp resp; | ||
| 253 | struct servreg_set_ack_req req; | ||
| 254 | struct qmi_txn txn; | ||
| 255 | int ret; | ||
| 256 | |||
| 257 | ret = qmi_txn_init(&pdr->notifier_hdl, &txn, servreg_set_ack_resp_ei, | ||
| 258 | &resp); | ||
| 259 | if (ret < 0) | ||
| 260 | return ret; | ||
| 261 | |||
| 262 | req.transaction_id = tid; | ||
| 263 | strcpy(req.service_path, pds->service_path); | ||
| 264 | |||
| 265 | ret = qmi_send_request(&pdr->notifier_hdl, &pds->addr, | ||
| 266 | &txn, SERVREG_SET_ACK_REQ, | ||
| 267 | SERVREG_SET_ACK_REQ_LEN, | ||
| 268 | servreg_set_ack_req_ei, | ||
| 269 | &req); | ||
| 270 | |||
| 271 | /* Skip waiting for response */ | ||
| 272 | qmi_txn_cancel(&txn); | ||
| 273 | return ret; | ||
| 274 | } | ||
| 275 | |||
| 276 | static void pdr_indack_work(struct work_struct *work) | ||
| 277 | { | ||
| 278 | struct pdr_handle *pdr = container_of(work, struct pdr_handle, | ||
| 279 | indack_work); | ||
| 280 | struct pdr_list_node *ind, *tmp; | ||
| 281 | struct pdr_service *pds; | ||
| 282 | |||
| 283 | list_for_each_entry_safe(ind, tmp, &pdr->indack_list, node) { | ||
| 284 | pds = ind->pds; | ||
| 285 | pdr_send_indack_msg(pdr, pds, ind->transaction_id); | ||
| 286 | |||
| 287 | mutex_lock(&pdr->status_lock); | ||
| 288 | pds->state = ind->curr_state; | ||
| 289 | pdr->status(pds->state, pds->service_path, pdr->priv); | ||
| 290 | mutex_unlock(&pdr->status_lock); | ||
| 291 | |||
| 292 | mutex_lock(&pdr->list_lock); | ||
| 293 | list_del(&ind->node); | ||
| 294 | mutex_unlock(&pdr->list_lock); | ||
| 295 | |||
| 296 | kfree(ind); | ||
| 297 | } | ||
| 298 | } | ||
| 299 | |||
| 300 | static void pdr_indication_cb(struct qmi_handle *qmi, | ||
| 301 | struct sockaddr_qrtr *sq, | ||
| 302 | struct qmi_txn *txn, const void *data) | ||
| 303 | { | ||
| 304 | struct pdr_handle *pdr = container_of(qmi, struct pdr_handle, | ||
| 305 | notifier_hdl); | ||
| 306 | const struct servreg_state_updated_ind *ind_msg = data; | ||
| 307 | struct pdr_list_node *ind; | ||
| 308 | struct pdr_service *pds; | ||
| 309 | bool found = false; | ||
| 310 | |||
| 311 | if (!ind_msg || !ind_msg->service_path[0] || | ||
| 312 | strlen(ind_msg->service_path) > SERVREG_NAME_LENGTH) | ||
| 313 | return; | ||
| 314 | |||
| 315 | mutex_lock(&pdr->list_lock); | ||
| 316 | list_for_each_entry(pds, &pdr->lookups, node) { | ||
| 317 | if (strcmp(pds->service_path, ind_msg->service_path)) | ||
| 318 | continue; | ||
| 319 | |||
| 320 | found = true; | ||
| 321 | break; | ||
| 322 | } | ||
| 323 | mutex_unlock(&pdr->list_lock); | ||
| 324 | |||
| 325 | if (!found) | ||
| 326 | return; | ||
| 327 | |||
| 328 | pr_info("PDR: Indication received from %s, state: 0x%x, trans-id: %d\n", | ||
| 329 | ind_msg->service_path, ind_msg->curr_state, | ||
| 330 | ind_msg->transaction_id); | ||
| 331 | |||
| 332 | ind = kzalloc(sizeof(*ind), GFP_KERNEL); | ||
| 333 | if (!ind) | ||
| 334 | return; | ||
| 335 | |||
| 336 | ind->transaction_id = ind_msg->transaction_id; | ||
| 337 | ind->curr_state = ind_msg->curr_state; | ||
| 338 | ind->pds = pds; | ||
| 339 | |||
| 340 | mutex_lock(&pdr->list_lock); | ||
| 341 | list_add_tail(&ind->node, &pdr->indack_list); | ||
| 342 | mutex_unlock(&pdr->list_lock); | ||
| 343 | |||
| 344 | queue_work(pdr->indack_wq, &pdr->indack_work); | ||
| 345 | } | ||
| 346 | |||
| 347 | static struct qmi_msg_handler qmi_indication_handler[] = { | ||
| 348 | { | ||
| 349 | .type = QMI_INDICATION, | ||
| 350 | .msg_id = SERVREG_STATE_UPDATED_IND_ID, | ||
| 351 | .ei = servreg_state_updated_ind_ei, | ||
| 352 | .decoded_size = sizeof(struct servreg_state_updated_ind), | ||
| 353 | .fn = pdr_indication_cb, | ||
| 354 | }, | ||
| 355 | {} | ||
| 356 | }; | ||
| 357 | |||
| 358 | static int pdr_get_domain_list(struct servreg_get_domain_list_req *req, | ||
| 359 | struct servreg_get_domain_list_resp *resp, | ||
| 360 | struct pdr_handle *pdr) | ||
| 361 | { | ||
| 362 | struct qmi_txn txn; | ||
| 363 | int ret; | ||
| 364 | |||
| 365 | ret = qmi_txn_init(&pdr->locator_hdl, &txn, | ||
| 366 | servreg_get_domain_list_resp_ei, resp); | ||
| 367 | if (ret < 0) | ||
| 368 | return ret; | ||
| 369 | |||
| 370 | ret = qmi_send_request(&pdr->locator_hdl, | ||
| 371 | &pdr->locator_addr, | ||
| 372 | &txn, SERVREG_GET_DOMAIN_LIST_REQ, | ||
| 373 | SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN, | ||
| 374 | servreg_get_domain_list_req_ei, | ||
| 375 | req); | ||
| 376 | if (ret < 0) { | ||
| 377 | qmi_txn_cancel(&txn); | ||
| 378 | return ret; | ||
| 379 | } | ||
| 380 | |||
| 381 | ret = qmi_txn_wait(&txn, 5 * HZ); | ||
| 382 | if (ret < 0) { | ||
| 383 | pr_err("PDR: %s get domain list txn wait failed: %d\n", | ||
| 384 | req->service_name, ret); | ||
| 385 | return ret; | ||
| 386 | } | ||
| 387 | |||
| 388 | if (resp->resp.result != QMI_RESULT_SUCCESS_V01) { | ||
| 389 | pr_err("PDR: %s get domain list failed: 0x%x\n", | ||
| 390 | req->service_name, resp->resp.error); | ||
| 391 | return -EREMOTEIO; | ||
| 392 | } | ||
| 393 | |||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) | ||
| 398 | { | ||
| 399 | struct servreg_get_domain_list_resp *resp; | ||
| 400 | struct servreg_get_domain_list_req req; | ||
| 401 | struct servreg_location_entry *entry; | ||
| 402 | int domains_read = 0; | ||
| 403 | int ret, i; | ||
| 404 | |||
| 405 | resp = kzalloc(sizeof(*resp), GFP_KERNEL); | ||
| 406 | if (!resp) | ||
| 407 | return -ENOMEM; | ||
| 408 | |||
| 409 | /* Prepare req message */ | ||
| 410 | strcpy(req.service_name, pds->service_name); | ||
| 411 | req.domain_offset_valid = true; | ||
| 412 | req.domain_offset = 0; | ||
| 413 | |||
| 414 | do { | ||
| 415 | req.domain_offset = domains_read; | ||
| 416 | ret = pdr_get_domain_list(&req, resp, pdr); | ||
| 417 | if (ret < 0) | ||
| 418 | goto out; | ||
| 419 | |||
| 420 | for (i = domains_read; i < resp->domain_list_len; i++) { | ||
| 421 | entry = &resp->domain_list[i]; | ||
| 422 | |||
| 423 | if (strnlen(entry->name, sizeof(entry->name)) == sizeof(entry->name)) | ||
| 424 | continue; | ||
| 425 | |||
| 426 | if (!strcmp(entry->name, pds->service_path)) { | ||
| 427 | pds->service_data_valid = entry->service_data_valid; | ||
| 428 | pds->service_data = entry->service_data; | ||
| 429 | pds->instance = entry->instance; | ||
| 430 | goto out; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | /* Update ret to indicate that the service is not yet found */ | ||
| 435 | ret = -ENXIO; | ||
| 436 | |||
| 437 | /* Always read total_domains from the response msg */ | ||
| 438 | if (resp->domain_list_len > resp->total_domains) | ||
| 439 | resp->domain_list_len = resp->total_domains; | ||
| 440 | |||
| 441 | domains_read += resp->domain_list_len; | ||
| 442 | } while (domains_read < resp->total_domains); | ||
| 443 | out: | ||
| 444 | kfree(resp); | ||
| 445 | return ret; | ||
| 446 | } | ||
| 447 | |||
| 448 | static void pdr_notify_lookup_failure(struct pdr_handle *pdr, | ||
| 449 | struct pdr_service *pds, | ||
| 450 | int err) | ||
| 451 | { | ||
| 452 | pr_err("PDR: service lookup for %s failed: %d\n", | ||
| 453 | pds->service_name, err); | ||
| 454 | |||
| 455 | if (err == -ENXIO) | ||
| 456 | return; | ||
| 457 | |||
| 458 | list_del(&pds->node); | ||
| 459 | pds->state = SERVREG_LOCATOR_ERR; | ||
| 460 | mutex_lock(&pdr->status_lock); | ||
| 461 | pdr->status(pds->state, pds->service_path, pdr->priv); | ||
| 462 | mutex_unlock(&pdr->status_lock); | ||
| 463 | kfree(pds); | ||
| 464 | } | ||
| 465 | |||
| 466 | static void pdr_locator_work(struct work_struct *work) | ||
| 467 | { | ||
| 468 | struct pdr_handle *pdr = container_of(work, struct pdr_handle, | ||
| 469 | locator_work); | ||
| 470 | struct pdr_service *pds, *tmp; | ||
| 471 | int ret = 0; | ||
| 472 | |||
| 473 | /* Bail out early if the SERVREG LOCATOR QMI service is not up */ | ||
| 474 | mutex_lock(&pdr->lock); | ||
| 475 | if (!pdr->locator_init_complete) { | ||
| 476 | mutex_unlock(&pdr->lock); | ||
| 477 | pr_debug("PDR: SERVICE LOCATOR service not available\n"); | ||
| 478 | return; | ||
| 479 | } | ||
| 480 | mutex_unlock(&pdr->lock); | ||
| 481 | |||
| 482 | mutex_lock(&pdr->list_lock); | ||
| 483 | list_for_each_entry_safe(pds, tmp, &pdr->lookups, node) { | ||
| 484 | if (!pds->need_locator_lookup) | ||
| 485 | continue; | ||
| 486 | |||
| 487 | ret = pdr_locate_service(pdr, pds); | ||
| 488 | if (ret < 0) { | ||
| 489 | pdr_notify_lookup_failure(pdr, pds, ret); | ||
| 490 | continue; | ||
| 491 | } | ||
| 492 | |||
| 493 | ret = qmi_add_lookup(&pdr->notifier_hdl, pds->service, 1, | ||
| 494 | pds->instance); | ||
| 495 | if (ret < 0) { | ||
| 496 | pdr_notify_lookup_failure(pdr, pds, ret); | ||
| 497 | continue; | ||
| 498 | } | ||
| 499 | |||
| 500 | pds->need_locator_lookup = false; | ||
| 501 | } | ||
| 502 | mutex_unlock(&pdr->list_lock); | ||
| 503 | } | ||
| 504 | |||
| 505 | /** | ||
| 506 | * pdr_add_lookup() - register a tracking request for a PD | ||
| 507 | * @pdr: PDR client handle | ||
| 508 | * @service_name: service name of the tracking request | ||
| 509 | * @service_path: service path of the tracking request | ||
| 510 | * | ||
| 511 | * Registering a pdr lookup allows for tracking the life cycle of the PD. | ||
| 512 | * | ||
| 513 | * Return: pdr_service object on success, ERR_PTR on failure. -EALREADY is | ||
| 514 | * returned if a lookup is already in progress for the given service path. | ||
| 515 | */ | ||
| 516 | struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, | ||
| 517 | const char *service_name, | ||
| 518 | const char *service_path) | ||
| 519 | { | ||
| 520 | struct pdr_service *pds, *tmp; | ||
| 521 | int ret; | ||
| 522 | |||
| 523 | if (IS_ERR_OR_NULL(pdr)) | ||
| 524 | return ERR_PTR(-EINVAL); | ||
| 525 | |||
| 526 | if (!service_name || strlen(service_name) > SERVREG_NAME_LENGTH || | ||
| 527 | !service_path || strlen(service_path) > SERVREG_NAME_LENGTH) | ||
| 528 | return ERR_PTR(-EINVAL); | ||
| 529 | |||
| 530 | pds = kzalloc(sizeof(*pds), GFP_KERNEL); | ||
| 531 | if (!pds) | ||
| 532 | return ERR_PTR(-ENOMEM); | ||
| 533 | |||
| 534 | pds->service = SERVREG_NOTIFIER_SERVICE; | ||
| 535 | strcpy(pds->service_name, service_name); | ||
| 536 | strcpy(pds->service_path, service_path); | ||
| 537 | pds->need_locator_lookup = true; | ||
| 538 | |||
| 539 | mutex_lock(&pdr->list_lock); | ||
| 540 | list_for_each_entry(tmp, &pdr->lookups, node) { | ||
| 541 | if (strcmp(tmp->service_path, service_path)) | ||
| 542 | continue; | ||
| 543 | |||
| 544 | mutex_unlock(&pdr->list_lock); | ||
| 545 | ret = -EALREADY; | ||
| 546 | goto err; | ||
| 547 | } | ||
| 548 | |||
| 549 | list_add(&pds->node, &pdr->lookups); | ||
| 550 | mutex_unlock(&pdr->list_lock); | ||
| 551 | |||
| 552 | schedule_work(&pdr->locator_work); | ||
| 553 | |||
| 554 | return pds; | ||
| 555 | err: | ||
| 556 | kfree(pds); | ||
| 557 | return ERR_PTR(ret); | ||
| 558 | } | ||
| 559 | EXPORT_SYMBOL(pdr_add_lookup); | ||
| 560 | |||
| 561 | /** | ||
| 562 | * pdr_restart_pd() - restart PD | ||
| 563 | * @pdr: PDR client handle | ||
| 564 | * @pds: PD service handle | ||
| 565 | * | ||
| 566 | * Restarts the PD tracked by the PDR client handle for a given service path. | ||
| 567 | * | ||
| 568 | * Return: 0 on success, negative errno on failure. | ||
| 569 | */ | ||
| 570 | int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds) | ||
| 571 | { | ||
| 572 | struct servreg_restart_pd_resp resp; | ||
| 573 | struct servreg_restart_pd_req req; | ||
| 574 | struct sockaddr_qrtr addr; | ||
| 575 | struct pdr_service *tmp; | ||
| 576 | struct qmi_txn txn; | ||
| 577 | int ret; | ||
| 578 | |||
| 579 | if (IS_ERR_OR_NULL(pdr) || IS_ERR_OR_NULL(pds)) | ||
| 580 | return -EINVAL; | ||
| 581 | |||
| 582 | mutex_lock(&pdr->list_lock); | ||
| 583 | list_for_each_entry(tmp, &pdr->lookups, node) { | ||
| 584 | if (tmp != pds) | ||
| 585 | continue; | ||
| 586 | |||
| 587 | if (!pds->service_connected) | ||
| 588 | break; | ||
| 589 | |||
| 590 | /* Prepare req message */ | ||
| 591 | strcpy(req.service_path, pds->service_path); | ||
| 592 | addr = pds->addr; | ||
| 593 | break; | ||
| 594 | } | ||
| 595 | mutex_unlock(&pdr->list_lock); | ||
| 596 | |||
| 597 | if (!req.service_path[0]) | ||
| 598 | return -EINVAL; | ||
| 599 | |||
| 600 | ret = qmi_txn_init(&pdr->notifier_hdl, &txn, | ||
| 601 | servreg_restart_pd_resp_ei, | ||
| 602 | &resp); | ||
| 603 | if (ret < 0) | ||
| 604 | return ret; | ||
| 605 | |||
| 606 | ret = qmi_send_request(&pdr->notifier_hdl, &addr, | ||
| 607 | &txn, SERVREG_RESTART_PD_REQ, | ||
| 608 | SERVREG_RESTART_PD_REQ_MAX_LEN, | ||
| 609 | servreg_restart_pd_req_ei, &req); | ||
| 610 | if (ret < 0) { | ||
| 611 | qmi_txn_cancel(&txn); | ||
| 612 | return ret; | ||
| 613 | } | ||
| 614 | |||
| 615 | ret = qmi_txn_wait(&txn, 5 * HZ); | ||
| 616 | if (ret < 0) { | ||
| 617 | pr_err("PDR: %s PD restart txn wait failed: %d\n", | ||
| 618 | req.service_path, ret); | ||
| 619 | return ret; | ||
| 620 | } | ||
| 621 | |||
| 622 | /* Check response if PDR is disabled */ | ||
| 623 | if (resp.resp.result == QMI_RESULT_FAILURE_V01 && | ||
| 624 | resp.resp.error == QMI_ERR_DISABLED_V01) { | ||
| 625 | pr_err("PDR: %s PD restart is disabled: 0x%x\n", | ||
| 626 | req.service_path, resp.resp.error); | ||
| 627 | return -EOPNOTSUPP; | ||
| 628 | } | ||
| 629 | |||
| 630 | /* Check the response for other error case*/ | ||
| 631 | if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { | ||
| 632 | pr_err("PDR: %s request for PD restart failed: 0x%x\n", | ||
| 633 | req.service_path, resp.resp.error); | ||
| 634 | return -EREMOTEIO; | ||
| 635 | } | ||
| 636 | |||
| 637 | return 0; | ||
| 638 | } | ||
| 639 | EXPORT_SYMBOL(pdr_restart_pd); | ||
| 640 | |||
| 641 | /** | ||
| 642 | * pdr_handle_alloc() - initialize the PDR client handle | ||
| 643 | * @status: function to be called on PD state change | ||
| 644 | * @priv: handle for client's use | ||
| 645 | * | ||
| 646 | * Initializes the PDR client handle to allow for tracking/restart of PDs. | ||
| 647 | * | ||
| 648 | * Return: pdr_handle object on success, ERR_PTR on failure. | ||
| 649 | */ | ||
| 650 | struct pdr_handle *pdr_handle_alloc(void (*status)(int state, | ||
| 651 | char *service_path, | ||
| 652 | void *priv), void *priv) | ||
| 653 | { | ||
| 654 | struct pdr_handle *pdr; | ||
| 655 | int ret; | ||
| 656 | |||
| 657 | if (!status) | ||
| 658 | return ERR_PTR(-EINVAL); | ||
| 659 | |||
| 660 | pdr = kzalloc(sizeof(*pdr), GFP_KERNEL); | ||
| 661 | if (!pdr) | ||
| 662 | return ERR_PTR(-ENOMEM); | ||
| 663 | |||
| 664 | pdr->status = status; | ||
| 665 | pdr->priv = priv; | ||
| 666 | |||
| 667 | mutex_init(&pdr->status_lock); | ||
| 668 | mutex_init(&pdr->list_lock); | ||
| 669 | mutex_init(&pdr->lock); | ||
| 670 | |||
| 671 | INIT_LIST_HEAD(&pdr->lookups); | ||
| 672 | INIT_LIST_HEAD(&pdr->indack_list); | ||
| 673 | |||
| 674 | INIT_WORK(&pdr->locator_work, pdr_locator_work); | ||
| 675 | INIT_WORK(&pdr->notifier_work, pdr_notifier_work); | ||
| 676 | INIT_WORK(&pdr->indack_work, pdr_indack_work); | ||
| 677 | |||
| 678 | pdr->notifier_wq = create_singlethread_workqueue("pdr_notifier_wq"); | ||
| 679 | if (!pdr->notifier_wq) { | ||
| 680 | ret = -ENOMEM; | ||
| 681 | goto free_pdr_handle; | ||
| 682 | } | ||
| 683 | |||
| 684 | pdr->indack_wq = alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI); | ||
| 685 | if (!pdr->indack_wq) { | ||
| 686 | ret = -ENOMEM; | ||
| 687 | goto destroy_notifier; | ||
| 688 | } | ||
| 689 | |||
| 690 | ret = qmi_handle_init(&pdr->locator_hdl, | ||
| 691 | SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN, | ||
| 692 | &pdr_locator_ops, NULL); | ||
| 693 | if (ret < 0) | ||
| 694 | goto destroy_indack; | ||
| 695 | |||
| 696 | ret = qmi_add_lookup(&pdr->locator_hdl, SERVREG_LOCATOR_SERVICE, 1, 1); | ||
| 697 | if (ret < 0) | ||
| 698 | goto release_qmi_handle; | ||
| 699 | |||
| 700 | ret = qmi_handle_init(&pdr->notifier_hdl, | ||
| 701 | SERVREG_STATE_UPDATED_IND_MAX_LEN, | ||
| 702 | &pdr_notifier_ops, | ||
| 703 | qmi_indication_handler); | ||
| 704 | if (ret < 0) | ||
| 705 | goto release_qmi_handle; | ||
| 706 | |||
| 707 | return pdr; | ||
| 708 | |||
| 709 | release_qmi_handle: | ||
| 710 | qmi_handle_release(&pdr->locator_hdl); | ||
| 711 | destroy_indack: | ||
| 712 | destroy_workqueue(pdr->indack_wq); | ||
| 713 | destroy_notifier: | ||
| 714 | destroy_workqueue(pdr->notifier_wq); | ||
| 715 | free_pdr_handle: | ||
| 716 | kfree(pdr); | ||
| 717 | |||
| 718 | return ERR_PTR(ret); | ||
| 719 | } | ||
| 720 | EXPORT_SYMBOL(pdr_handle_alloc); | ||
| 721 | |||
| 722 | /** | ||
| 723 | * pdr_handle_release() - release the PDR client handle | ||
| 724 | * @pdr: PDR client handle | ||
| 725 | * | ||
| 726 | * Cleans up pending tracking requests and releases the underlying qmi handles. | ||
| 727 | */ | ||
| 728 | void pdr_handle_release(struct pdr_handle *pdr) | ||
| 729 | { | ||
| 730 | struct pdr_service *pds, *tmp; | ||
| 731 | |||
| 732 | if (IS_ERR_OR_NULL(pdr)) | ||
| 733 | return; | ||
| 734 | |||
| 735 | mutex_lock(&pdr->list_lock); | ||
| 736 | list_for_each_entry_safe(pds, tmp, &pdr->lookups, node) { | ||
| 737 | list_del(&pds->node); | ||
| 738 | kfree(pds); | ||
| 739 | } | ||
| 740 | mutex_unlock(&pdr->list_lock); | ||
| 741 | |||
| 742 | cancel_work_sync(&pdr->locator_work); | ||
| 743 | cancel_work_sync(&pdr->notifier_work); | ||
| 744 | cancel_work_sync(&pdr->indack_work); | ||
| 745 | |||
| 746 | destroy_workqueue(pdr->notifier_wq); | ||
| 747 | destroy_workqueue(pdr->indack_wq); | ||
| 748 | |||
| 749 | qmi_handle_release(&pdr->locator_hdl); | ||
| 750 | qmi_handle_release(&pdr->notifier_hdl); | ||
| 751 | |||
| 752 | kfree(pdr); | ||
| 753 | } | ||
| 754 | EXPORT_SYMBOL(pdr_handle_release); | ||
| 755 | |||
| 756 | MODULE_LICENSE("GPL v2"); | ||
| 757 | MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers"); | ||
| @@ -0,0 +1,379 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef __QCOM_PDR_HELPER_INTERNAL__ | ||
| 3 | #define __QCOM_PDR_HELPER_INTERNAL__ | ||
| 4 | |||
| 5 | #include <linux/soc/qcom/pdr.h> | ||
| 6 | |||
| 7 | #define SERVREG_LOCATOR_SERVICE 0x40 | ||
| 8 | #define SERVREG_NOTIFIER_SERVICE 0x42 | ||
| 9 | |||
| 10 | #define SERVREG_REGISTER_LISTENER_REQ 0x20 | ||
| 11 | #define SERVREG_GET_DOMAIN_LIST_REQ 0x21 | ||
| 12 | #define SERVREG_STATE_UPDATED_IND_ID 0x22 | ||
| 13 | #define SERVREG_SET_ACK_REQ 0x23 | ||
| 14 | #define SERVREG_RESTART_PD_REQ 0x24 | ||
| 15 | |||
| 16 | #define SERVREG_DOMAIN_LIST_LENGTH 32 | ||
| 17 | #define SERVREG_RESTART_PD_REQ_MAX_LEN 67 | ||
| 18 | #define SERVREG_REGISTER_LISTENER_REQ_LEN 71 | ||
| 19 | #define SERVREG_SET_ACK_REQ_LEN 72 | ||
| 20 | #define SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN 74 | ||
| 21 | #define SERVREG_STATE_UPDATED_IND_MAX_LEN 79 | ||
| 22 | #define SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN 2389 | ||
| 23 | |||
| 24 | struct servreg_location_entry { | ||
| 25 | char name[SERVREG_NAME_LENGTH + 1]; | ||
| 26 | u8 service_data_valid; | ||
| 27 | u32 service_data; | ||
| 28 | u32 instance; | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct qmi_elem_info servreg_location_entry_ei[] = { | ||
| 32 | { | ||
| 33 | .data_type = QMI_STRING, | ||
| 34 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 35 | .elem_size = sizeof(char), | ||
| 36 | .array_type = NO_ARRAY, | ||
| 37 | .tlv_type = 0, | ||
| 38 | .offset = offsetof(struct servreg_location_entry, | ||
| 39 | name), | ||
| 40 | }, | ||
| 41 | { | ||
| 42 | .data_type = QMI_UNSIGNED_4_BYTE, | ||
| 43 | .elem_len = 1, | ||
| 44 | .elem_size = sizeof(u32), | ||
| 45 | .array_type = NO_ARRAY, | ||
| 46 | .tlv_type = 0, | ||
| 47 | .offset = offsetof(struct servreg_location_entry, | ||
| 48 | instance), | ||
| 49 | }, | ||
| 50 | { | ||
| 51 | .data_type = QMI_UNSIGNED_1_BYTE, | ||
| 52 | .elem_len = 1, | ||
| 53 | .elem_size = sizeof(u8), | ||
| 54 | .array_type = NO_ARRAY, | ||
| 55 | .tlv_type = 0, | ||
| 56 | .offset = offsetof(struct servreg_location_entry, | ||
| 57 | service_data_valid), | ||
| 58 | }, | ||
| 59 | { | ||
| 60 | .data_type = QMI_UNSIGNED_4_BYTE, | ||
| 61 | .elem_len = 1, | ||
| 62 | .elem_size = sizeof(u32), | ||
| 63 | .array_type = NO_ARRAY, | ||
| 64 | .tlv_type = 0, | ||
| 65 | .offset = offsetof(struct servreg_location_entry, | ||
| 66 | service_data), | ||
| 67 | }, | ||
| 68 | {} | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct servreg_get_domain_list_req { | ||
| 72 | char service_name[SERVREG_NAME_LENGTH + 1]; | ||
| 73 | u8 domain_offset_valid; | ||
| 74 | u32 domain_offset; | ||
| 75 | }; | ||
| 76 | |||
| 77 | struct qmi_elem_info servreg_get_domain_list_req_ei[] = { | ||
| 78 | { | ||
| 79 | .data_type = QMI_STRING, | ||
| 80 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 81 | .elem_size = sizeof(char), | ||
| 82 | .array_type = NO_ARRAY, | ||
| 83 | .tlv_type = 0x01, | ||
| 84 | .offset = offsetof(struct servreg_get_domain_list_req, | ||
| 85 | service_name), | ||
| 86 | }, | ||
| 87 | { | ||
| 88 | .data_type = QMI_OPT_FLAG, | ||
| 89 | .elem_len = 1, | ||
| 90 | .elem_size = sizeof(u8), | ||
| 91 | .array_type = NO_ARRAY, | ||
| 92 | .tlv_type = 0x10, | ||
| 93 | .offset = offsetof(struct servreg_get_domain_list_req, | ||
| 94 | domain_offset_valid), | ||
| 95 | }, | ||
| 96 | { | ||
| 97 | .data_type = QMI_UNSIGNED_4_BYTE, | ||
| 98 | .elem_len = 1, | ||
| 99 | .elem_size = sizeof(u32), | ||
| 100 | .array_type = NO_ARRAY, | ||
| 101 | .tlv_type = 0x10, | ||
| 102 | .offset = offsetof(struct servreg_get_domain_list_req, | ||
| 103 | domain_offset), | ||
| 104 | }, | ||
| 105 | {} | ||
| 106 | }; | ||
| 107 | |||
| 108 | struct servreg_get_domain_list_resp { | ||
| 109 | struct qmi_response_type_v01 resp; | ||
| 110 | u8 total_domains_valid; | ||
| 111 | u16 total_domains; | ||
| 112 | u8 db_rev_count_valid; | ||
| 113 | u16 db_rev_count; | ||
| 114 | u8 domain_list_valid; | ||
| 115 | u32 domain_list_len; | ||
| 116 | struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH]; | ||
| 117 | }; | ||
| 118 | |||
| 119 | struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { | ||
| 120 | { | ||
| 121 | .data_type = QMI_STRUCT, | ||
| 122 | .elem_len = 1, | ||
| 123 | .elem_size = sizeof(struct qmi_response_type_v01), | ||
| 124 | .array_type = NO_ARRAY, | ||
| 125 | .tlv_type = 0x02, | ||
| 126 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 127 | resp), | ||
| 128 | .ei_array = qmi_response_type_v01_ei, | ||
| 129 | }, | ||
| 130 | { | ||
| 131 | .data_type = QMI_OPT_FLAG, | ||
| 132 | .elem_len = 1, | ||
| 133 | .elem_size = sizeof(u8), | ||
| 134 | .array_type = NO_ARRAY, | ||
| 135 | .tlv_type = 0x10, | ||
| 136 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 137 | total_domains_valid), | ||
| 138 | }, | ||
| 139 | { | ||
| 140 | .data_type = QMI_UNSIGNED_2_BYTE, | ||
| 141 | .elem_len = 1, | ||
| 142 | .elem_size = sizeof(u16), | ||
| 143 | .array_type = NO_ARRAY, | ||
| 144 | .tlv_type = 0x10, | ||
| 145 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 146 | total_domains), | ||
| 147 | }, | ||
| 148 | { | ||
| 149 | .data_type = QMI_OPT_FLAG, | ||
| 150 | .elem_len = 1, | ||
| 151 | .elem_size = sizeof(u8), | ||
| 152 | .array_type = NO_ARRAY, | ||
| 153 | .tlv_type = 0x11, | ||
| 154 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 155 | db_rev_count_valid), | ||
| 156 | }, | ||
| 157 | { | ||
| 158 | .data_type = QMI_UNSIGNED_2_BYTE, | ||
| 159 | .elem_len = 1, | ||
| 160 | .elem_size = sizeof(u16), | ||
| 161 | .array_type = NO_ARRAY, | ||
| 162 | .tlv_type = 0x11, | ||
| 163 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 164 | db_rev_count), | ||
| 165 | }, | ||
| 166 | { | ||
| 167 | .data_type = QMI_OPT_FLAG, | ||
| 168 | .elem_len = 1, | ||
| 169 | .elem_size = sizeof(u8), | ||
| 170 | .array_type = NO_ARRAY, | ||
| 171 | .tlv_type = 0x12, | ||
| 172 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 173 | domain_list_valid), | ||
| 174 | }, | ||
| 175 | { | ||
| 176 | .data_type = QMI_DATA_LEN, | ||
| 177 | .elem_len = 1, | ||
| 178 | .elem_size = sizeof(u8), | ||
| 179 | .array_type = NO_ARRAY, | ||
| 180 | .tlv_type = 0x12, | ||
| 181 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 182 | domain_list_len), | ||
| 183 | }, | ||
| 184 | { | ||
| 185 | .data_type = QMI_STRUCT, | ||
| 186 | .elem_len = SERVREG_DOMAIN_LIST_LENGTH, | ||
| 187 | .elem_size = sizeof(struct servreg_location_entry), | ||
| 188 | .array_type = NO_ARRAY, | ||
| 189 | .tlv_type = 0x12, | ||
| 190 | .offset = offsetof(struct servreg_get_domain_list_resp, | ||
| 191 | domain_list), | ||
| 192 | .ei_array = servreg_location_entry_ei, | ||
| 193 | }, | ||
| 194 | {} | ||
| 195 | }; | ||
| 196 | |||
| 197 | struct servreg_register_listener_req { | ||
| 198 | u8 enable; | ||
| 199 | char service_path[SERVREG_NAME_LENGTH + 1]; | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct qmi_elem_info servreg_register_listener_req_ei[] = { | ||
| 203 | { | ||
| 204 | .data_type = QMI_UNSIGNED_1_BYTE, | ||
| 205 | .elem_len = 1, | ||
| 206 | .elem_size = sizeof(u8), | ||
| 207 | .array_type = NO_ARRAY, | ||
| 208 | .tlv_type = 0x01, | ||
| 209 | .offset = offsetof(struct servreg_register_listener_req, | ||
| 210 | enable), | ||
| 211 | }, | ||
| 212 | { | ||
| 213 | .data_type = QMI_STRING, | ||
| 214 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 215 | .elem_size = sizeof(char), | ||
| 216 | .array_type = NO_ARRAY, | ||
| 217 | .tlv_type = 0x02, | ||
| 218 | .offset = offsetof(struct servreg_register_listener_req, | ||
| 219 | service_path), | ||
| 220 | }, | ||
| 221 | {} | ||
| 222 | }; | ||
| 223 | |||
| 224 | struct servreg_register_listener_resp { | ||
| 225 | struct qmi_response_type_v01 resp; | ||
| 226 | u8 curr_state_valid; | ||
| 227 | enum servreg_service_state curr_state; | ||
| 228 | }; | ||
| 229 | |||
| 230 | struct qmi_elem_info servreg_register_listener_resp_ei[] = { | ||
| 231 | { | ||
| 232 | .data_type = QMI_STRUCT, | ||
| 233 | .elem_len = 1, | ||
| 234 | .elem_size = sizeof(struct qmi_response_type_v01), | ||
| 235 | .array_type = NO_ARRAY, | ||
| 236 | .tlv_type = 0x02, | ||
| 237 | .offset = offsetof(struct servreg_register_listener_resp, | ||
| 238 | resp), | ||
| 239 | .ei_array = qmi_response_type_v01_ei, | ||
| 240 | }, | ||
| 241 | { | ||
| 242 | .data_type = QMI_OPT_FLAG, | ||
| 243 | .elem_len = 1, | ||
| 244 | .elem_size = sizeof(u8), | ||
| 245 | .array_type = NO_ARRAY, | ||
| 246 | .tlv_type = 0x10, | ||
| 247 | .offset = offsetof(struct servreg_register_listener_resp, | ||
| 248 | curr_state_valid), | ||
| 249 | }, | ||
| 250 | { | ||
| 251 | .data_type = QMI_SIGNED_4_BYTE_ENUM, | ||
| 252 | .elem_len = 1, | ||
| 253 | .elem_size = sizeof(enum servreg_service_state), | ||
| 254 | .array_type = NO_ARRAY, | ||
| 255 | .tlv_type = 0x10, | ||
| 256 | .offset = offsetof(struct servreg_register_listener_resp, | ||
| 257 | curr_state), | ||
| 258 | }, | ||
| 259 | {} | ||
| 260 | }; | ||
| 261 | |||
| 262 | struct servreg_restart_pd_req { | ||
| 263 | char service_path[SERVREG_NAME_LENGTH + 1]; | ||
| 264 | }; | ||
| 265 | |||
| 266 | struct qmi_elem_info servreg_restart_pd_req_ei[] = { | ||
| 267 | { | ||
| 268 | .data_type = QMI_STRING, | ||
| 269 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 270 | .elem_size = sizeof(char), | ||
| 271 | .array_type = NO_ARRAY, | ||
| 272 | .tlv_type = 0x01, | ||
| 273 | .offset = offsetof(struct servreg_restart_pd_req, | ||
| 274 | service_path), | ||
| 275 | }, | ||
| 276 | {} | ||
| 277 | }; | ||
| 278 | |||
| 279 | struct servreg_restart_pd_resp { | ||
| 280 | struct qmi_response_type_v01 resp; | ||
| 281 | }; | ||
| 282 | |||
| 283 | struct qmi_elem_info servreg_restart_pd_resp_ei[] = { | ||
| 284 | { | ||
| 285 | .data_type = QMI_STRUCT, | ||
| 286 | .elem_len = 1, | ||
| 287 | .elem_size = sizeof(struct qmi_response_type_v01), | ||
| 288 | .array_type = NO_ARRAY, | ||
| 289 | .tlv_type = 0x02, | ||
| 290 | .offset = offsetof(struct servreg_restart_pd_resp, | ||
| 291 | resp), | ||
| 292 | .ei_array = qmi_response_type_v01_ei, | ||
| 293 | }, | ||
| 294 | {} | ||
| 295 | }; | ||
| 296 | |||
| 297 | struct servreg_state_updated_ind { | ||
| 298 | enum servreg_service_state curr_state; | ||
| 299 | char service_path[SERVREG_NAME_LENGTH + 1]; | ||
| 300 | u16 transaction_id; | ||
| 301 | }; | ||
| 302 | |||
| 303 | struct qmi_elem_info servreg_state_updated_ind_ei[] = { | ||
| 304 | { | ||
| 305 | .data_type = QMI_SIGNED_4_BYTE_ENUM, | ||
| 306 | .elem_len = 1, | ||
| 307 | .elem_size = sizeof(u32), | ||
| 308 | .array_type = NO_ARRAY, | ||
| 309 | .tlv_type = 0x01, | ||
| 310 | .offset = offsetof(struct servreg_state_updated_ind, | ||
| 311 | curr_state), | ||
| 312 | }, | ||
| 313 | { | ||
| 314 | .data_type = QMI_STRING, | ||
| 315 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 316 | .elem_size = sizeof(char), | ||
| 317 | .array_type = NO_ARRAY, | ||
| 318 | .tlv_type = 0x02, | ||
| 319 | .offset = offsetof(struct servreg_state_updated_ind, | ||
| 320 | service_path), | ||
| 321 | }, | ||
| 322 | { | ||
| 323 | .data_type = QMI_UNSIGNED_2_BYTE, | ||
| 324 | .elem_len = 1, | ||
| 325 | .elem_size = sizeof(u16), | ||
| 326 | .array_type = NO_ARRAY, | ||
| 327 | .tlv_type = 0x03, | ||
| 328 | .offset = offsetof(struct servreg_state_updated_ind, | ||
| 329 | transaction_id), | ||
| 330 | }, | ||
| 331 | {} | ||
| 332 | }; | ||
| 333 | |||
| 334 | struct servreg_set_ack_req { | ||
| 335 | char service_path[SERVREG_NAME_LENGTH + 1]; | ||
| 336 | u16 transaction_id; | ||
| 337 | }; | ||
| 338 | |||
| 339 | struct qmi_elem_info servreg_set_ack_req_ei[] = { | ||
| 340 | { | ||
| 341 | .data_type = QMI_STRING, | ||
| 342 | .elem_len = SERVREG_NAME_LENGTH + 1, | ||
| 343 | .elem_size = sizeof(char), | ||
| 344 | .array_type = NO_ARRAY, | ||
| 345 | .tlv_type = 0x01, | ||
| 346 | .offset = offsetof(struct servreg_set_ack_req, | ||
| 347 | service_path), | ||
| 348 | }, | ||
| 349 | { | ||
| 350 | .data_type = QMI_UNSIGNED_2_BYTE, | ||
| 351 | .elem_len = 1, | ||
| 352 | .elem_size = sizeof(u16), | ||
| 353 | .array_type = NO_ARRAY, | ||
| 354 | .tlv_type = 0x02, | ||
| 355 | .offset = offsetof(struct servreg_set_ack_req, | ||
| 356 | transaction_id), | ||
| 357 | }, | ||
| 358 | {} | ||
| 359 | }; | ||
| 360 | |||
| 361 | struct servreg_set_ack_resp { | ||
| 362 | struct qmi_response_type_v01 resp; | ||
| 363 | }; | ||
| 364 | |||
| 365 | struct qmi_elem_info servreg_set_ack_resp_ei[] = { | ||
| 366 | { | ||
| 367 | .data_type = QMI_STRUCT, | ||
| 368 | .elem_len = 1, | ||
| 369 | .elem_size = sizeof(struct qmi_response_type_v01), | ||
| 370 | .array_type = NO_ARRAY, | ||
| 371 | .tlv_type = 0x02, | ||
| 372 | .offset = offsetof(struct servreg_set_ack_resp, | ||
| 373 | resp), | ||
| 374 | .ei_array = qmi_response_type_v01_ei, | ||
| 375 | }, | ||
| 376 | {} | ||
| 377 | }; | ||
| 378 | |||
| 379 | #endif | ||
| @@ -200,7 +200,7 @@ static irqreturn_t qmp_intr(int irq, void *data) · 199 unmodified lines | |||
| 200 | { | 200 | { |
| 201 | struct qmp *qmp = data; | 201 | struct qmp *qmp = data; |
| 202 | 202 | ||
| 203 | wake_up_interruptible_all(&qmp->event); | 203 | wake_up_all(&qmp->event); |
| 204 | 204 | ||
| 205 | return IRQ_HANDLED; | 205 | return IRQ_HANDLED; |
| 206 | } | 206 | } |
| @@ -225,6 +225,7 @@ static bool qmp_message_empty(struct qmp *qmp) · 18 unmodified lines | |||
| 225 | static int qmp_send(struct qmp *qmp, const void *data, size_t len) | 225 | static int qmp_send(struct qmp *qmp, const void *data, size_t len) |
| 226 | { | 226 | { |
| 227 | long time_left; | 227 | long time_left; |
| 228 | size_t tlen; | ||
| 228 | int ret; | 229 | int ret; |
| 229 | 230 | ||
| 230 | if (WARN_ON(len + sizeof(u32) > qmp->size)) | 231 | if (WARN_ON(len + sizeof(u32) > qmp->size)) |
| @@ -239,6 +240,9 @@ static int qmp_send(struct qmp *qmp, const void *data, size_t len) · 8 unmodified lines | |||
| 239 | __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32), | 240 | __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32), |
| 240 | data, len / sizeof(u32)); | 241 | data, len / sizeof(u32)); |
| 241 | writel(len, qmp->msgram + qmp->offset); | 242 | writel(len, qmp->msgram + qmp->offset); |
| 243 | |||
| 244 | /* Read back len to confirm data written in message RAM */ | ||
| 245 | tlen = readl(qmp->msgram + qmp->offset); | ||
| 242 | qmp_kick(qmp); | 246 | qmp_kick(qmp); |
| 243 | 247 | ||
| 244 | time_left = wait_event_interruptible_timeout(qmp->event, | 248 | time_left = wait_event_interruptible_timeout(qmp->event, |
| @@ -110,5 +110,6 @@ int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv, · 109 unmodified lines | |||
| 110 | int rpmh_rsc_invalidate(struct rsc_drv *drv); | 110 | int rpmh_rsc_invalidate(struct rsc_drv *drv); |
| 111 | 111 | ||
| 112 | void rpmh_tx_done(const struct tcs_request *msg, int r); | 112 | void rpmh_tx_done(const struct tcs_request *msg, int r); |
| 113 | int rpmh_flush(struct rpmh_ctrlr *ctrlr); | ||
| 113 | 114 | ||
| 114 | #endif /* __RPM_INTERNAL_H__ */ | 115 | #endif /* __RPM_INTERNAL_H__ */ |
| @@ -277,7 +277,7 @@ static void __tcs_buffer_write(struct rsc_drv *drv, int tcs_id, int cmd_id, · 276 unmodified lines | |||
| 277 | write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid); | 277 | write_tcs_cmd(drv, RSC_DRV_CMD_MSGID, tcs_id, j, msgid); |
| 278 | write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr); | 278 | write_tcs_cmd(drv, RSC_DRV_CMD_ADDR, tcs_id, j, cmd->addr); |
| 279 | write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data); | 279 | write_tcs_cmd(drv, RSC_DRV_CMD_DATA, tcs_id, j, cmd->data); |
| 280 | trace_rpmh_send_msg(drv, tcs_id, j, msgid, cmd); | 280 | trace_rpmh_send_msg_rcuidle(drv, tcs_id, j, msgid, cmd); |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete); | 283 | write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, cmd_complete); |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | #define RPMH_TIMEOUT_MS msecs_to_jiffies(10000) | 24 | #define RPMH_TIMEOUT_MS msecs_to_jiffies(10000) |
| 25 | 25 | ||
| 26 | #define DEFINE_RPMH_MSG_ONSTACK(dev, s, q, name) \ | 26 | #define DEFINE_RPMH_MSG_ONSTACK(device, s, q, name) \ |
| 27 | struct rpmh_request name = { \ | 27 | struct rpmh_request name = { \ |
| 28 | .msg = { \ | 28 | .msg = { \ |
| 29 | .state = s, \ | 29 | .state = s, \ |
| @@ -33,7 +33,7 @@ · 3 unmodified lines | |||
| 33 | }, \ | 33 | }, \ |
| 34 | .cmd = { { 0 } }, \ | 34 | .cmd = { { 0 } }, \ |
| 35 | .completion = q, \ | 35 | .completion = q, \ |
| 36 | .dev = dev, \ | 36 | .dev = device, \ |
| 37 | .needs_free = false, \ | 37 | .needs_free = false, \ |
| 38 | } | 38 | } |
| 39 | 39 | ||
| @@ -427,11 +427,10 @@ static int is_req_valid(struct cache_req *req) · 387 unmodified lines | |||
| 427 | req->sleep_val != req->wake_val); | 427 | req->sleep_val != req->wake_val); |
| 428 | } | 428 | } |
| 429 | 429 | ||
| 430 | static int send_single(const struct device *dev, enum rpmh_state state, | 430 | static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state, |
| 431 | u32 addr, u32 data) | 431 | u32 addr, u32 data) |
| 432 | { | 432 | { |
| 433 | DEFINE_RPMH_MSG_ONSTACK(dev, state, NULL, rpm_msg); | 433 | DEFINE_RPMH_MSG_ONSTACK(NULL, state, NULL, rpm_msg); |
| 434 | struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); | ||
| 435 | 434 | ||
| 436 | /* Wake sets are always complete and sleep sets are not */ | 435 | /* Wake sets are always complete and sleep sets are not */ |
| 437 | rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE); | 436 | rpm_msg.msg.wait_for_compl = (state == RPMH_WAKE_ONLY_STATE); |
| @@ -445,7 +444,7 @@ static int send_single(const struct device *dev, enum rpmh_state state, · 7 unmodified lines | |||
| 445 | /** | 444 | /** |
| 446 | * rpmh_flush: Flushes the buffered active and sleep sets to TCS | 445 | * rpmh_flush: Flushes the buffered active and sleep sets to TCS |
| 447 | * | 446 | * |
| 448 | * @dev: The device making the request | 447 | * @ctrlr: controller making request to flush cached data |
| 449 | * | 448 | * |
| 450 | * Return: -EBUSY if the controller is busy, probably waiting on a response | 449 | * Return: -EBUSY if the controller is busy, probably waiting on a response |
| 451 | * to a RPMH request sent earlier. | 450 | * to a RPMH request sent earlier. |
| @@ -454,10 +453,9 @@ static int send_single(const struct device *dev, enum rpmh_state state, · 2 unmodified lines | |||
| 454 | * that is powering down the entire system. Since no other RPMH API would be | 453 | * that is powering down the entire system. Since no other RPMH API would be |
| 455 | * executing at this time, it is safe to run lockless. | 454 | * executing at this time, it is safe to run lockless. |
| 456 | */ | 455 | */ |
| 457 | int rpmh_flush(const struct device *dev) | 456 | int rpmh_flush(struct rpmh_ctrlr *ctrlr) |
| 458 | { | 457 | { |
| 459 | struct cache_req *p; | 458 | struct cache_req *p; |
| 460 | struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev); | ||
| 461 | int ret; | 459 | int ret; |
| 462 | 460 | ||
| 463 | if (!ctrlr->dirty) { | 461 | if (!ctrlr->dirty) { |
| @@ -480,11 +478,12 @@ int rpmh_flush(const struct device *dev) · 16 unmodified lines | |||
| 480 | __func__, p->addr, p->sleep_val, p->wake_val); | 478 | __func__, p->addr, p->sleep_val, p->wake_val); |
| 481 | continue; | 479 | continue; |
| 482 | } | 480 | } |
| 483 | ret = send_single(dev, RPMH_SLEEP_STATE, p->addr, p->sleep_val); | 481 | ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr, |
| 482 | p->sleep_val); | ||
| 484 | if (ret) | 483 | if (ret) |
| 485 | return ret; | 484 | return ret; |
| 486 | ret = send_single(dev, RPMH_WAKE_ONLY_STATE, | 485 | ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr, |
| 487 | p->addr, p->wake_val); | 486 | p->wake_val); |
| 488 | if (ret) | 487 | if (ret) |
| 489 | return ret; | 488 | return ret; |
| 490 | } | 489 | } |
| @@ -493,7 +492,6 @@ int rpmh_flush(const struct device *dev) · 2 unmodified lines | |||
| 493 | 492 | ||
| 494 | return 0; | 493 | return 0; |
| 495 | } | 494 | } |
| 496 | EXPORT_SYMBOL(rpmh_flush); | ||
| 497 | 495 | ||
| 498 | /** | 496 | /** |
| 499 | * rpmh_invalidate: Invalidate all sleep and active sets | 497 | * rpmh_invalidate: Invalidate all sleep and active sets |
| @@ -277,7 +277,7 @@ static int show_image_##type(struct seq_file *seq, void *p) \ · 276 unmodified lines | |||
| 277 | { \ | 277 | { \ |
| 278 | struct smem_image_version *image_version = seq->private; \ | 278 | struct smem_image_version *image_version = seq->private; \ |
| 279 | seq_puts(seq, image_version->type); \ | 279 | seq_puts(seq, image_version->type); \ |
| 280 | seq_puts(seq, "\n"); \ | 280 | seq_putc(seq, '\n'); \ |
| 281 | return 0; \ | 281 | return 0; \ |
| 282 | } \ | 282 | } \ |
| 283 | static int open_image_##type(struct inode *inode, struct file *file) \ | 283 | static int open_image_##type(struct inode *inode, struct file *file) \ |
| @@ -195,19 +195,19 @@ config ARCH_R8A774C0 · 194 unmodified lines | |||
| 195 | This enables support for the Renesas RZ/G2E SoC. | 195 | This enables support for the Renesas RZ/G2E SoC. |
| 196 | 196 | ||
| 197 | config ARCH_R8A77950 | 197 | config ARCH_R8A77950 |
| 198 | bool | 198 | bool "Renesas R-Car H3 ES1.x SoC Platform" |
| 199 | select ARCH_RCAR_GEN3 | ||
| 200 | select SYSC_R8A7795 | ||
| 201 | help | ||
| 202 | This enables support for the Renesas R-Car H3 SoC (revision 1.x). | ||
| 199 | 203 | ||
| 200 | config ARCH_R8A77951 | 204 | config ARCH_R8A77951 |
| 201 | bool | 205 | bool "Renesas R-Car H3 ES2.0+ SoC Platform" |
| 202 | |||
| 203 | config ARCH_R8A7795 | ||
| 204 | bool "Renesas R-Car H3 SoC Platform" | ||
| 205 | select ARCH_R8A77950 | ||
| 206 | select ARCH_R8A77951 | ||
| 207 | select ARCH_RCAR_GEN3 | 206 | select ARCH_RCAR_GEN3 |
| 208 | select SYSC_R8A7795 | 207 | select SYSC_R8A7795 |
| 209 | help | 208 | help |
| 210 | This enables support for the Renesas R-Car H3 SoC. | 209 | This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and |
| 210 | later). | ||
| 211 | 211 | ||
| 212 | config ARCH_R8A77960 | 212 | config ARCH_R8A77960 |
| 213 | bool "Renesas R-Car M3-W SoC Platform" | 213 | bool "Renesas R-Car M3-W SoC Platform" |
| @@ -1,5 +1,5 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | * | 2 | /* |
| 3 | * Renesas R-Car System Controller | 3 | * Renesas R-Car System Controller |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2016 Glider bvba | 5 | * Copyright (C) 2016 Glider bvba |
| @@ -259,7 +259,7 @@ static const struct of_device_id renesas_socs[] __initconst = { · 258 unmodified lines | |||
| 259 | #ifdef CONFIG_ARCH_R8A7794 | 259 | #ifdef CONFIG_ARCH_R8A7794 |
| 260 | { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, | 260 | { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, |
| 261 | #endif | 261 | #endif |
| 262 | #ifdef CONFIG_ARCH_R8A7795 | 262 | #if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951) |
| 263 | { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, | 263 | { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, |
| 264 | #endif | 264 | #endif |
| 265 | #ifdef CONFIG_ARCH_R8A77960 | 265 | #ifdef CONFIG_ARCH_R8A77960 |
| @@ -44,7 +44,6 @@ static struct tee_context *teedev_open(struct tee_device *teedev) · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | kref_init(&ctx->refcount); | 45 | kref_init(&ctx->refcount); |
| 46 | ctx->teedev = teedev; | 46 | ctx->teedev = teedev; |
| 47 | INIT_LIST_HEAD(&ctx->list_shm); | ||
| 48 | rc = teedev->desc->ops->open(ctx); | 47 | rc = teedev->desc->ops->open(ctx); |
| 49 | if (rc) | 48 | if (rc) |
| 50 | goto err; | 49 | goto err; |
| @@ -37,7 +37,8 @@ struct tee_shm_pool { · 36 unmodified lines | |||
| 37 | * @num_users: number of active users of this device | 37 | * @num_users: number of active users of this device |
| 38 | * @c_no_user: completion used when unregistering the device | 38 | * @c_no_user: completion used when unregistering the device |
| 39 | * @mutex: mutex protecting @num_users and @idr | 39 | * @mutex: mutex protecting @num_users and @idr |
| 40 | * @idr: register of shared memory object allocated on this device | 40 | * @idr: register of user space shared memory objects allocated or |
| 41 | * registered on this device | ||
| 41 | * @pool: shared memory pool | 42 | * @pool: shared memory pool |
| 42 | */ | 43 | */ |
| 43 | struct tee_device { | 44 | struct tee_device { |
| @@ -13,13 +13,13 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | static void tee_shm_release(struct tee_shm *shm) | 14 | static void tee_shm_release(struct tee_shm *shm) |
| 15 | { | 15 | { |
| 16 | struct tee_device *teedev = shm->teedev; | 16 | struct tee_device *teedev = shm->ctx->teedev; |
| 17 | 17 | ||
| 18 | mutex_lock(&teedev->mutex); | 18 | if (shm->flags & TEE_SHM_DMA_BUF) { |
| 19 | idr_remove(&teedev->idr, shm->id); | 19 | mutex_lock(&teedev->mutex); |
| 20 | if (shm->ctx) | 20 | idr_remove(&teedev->idr, shm->id); |
| 21 | list_del(&shm->link); | 21 | mutex_unlock(&teedev->mutex); |
| 22 | mutex_unlock(&teedev->mutex); | 22 | } |
| 23 | 23 | ||
| 24 | if (shm->flags & TEE_SHM_POOL) { | 24 | if (shm->flags & TEE_SHM_POOL) { |
| 25 | struct tee_shm_pool_mgr *poolm; | 25 | struct tee_shm_pool_mgr *poolm; |
| @@ -44,8 +44,7 @@ static void tee_shm_release(struct tee_shm *shm) · 18 unmodified lines | |||
| 44 | kfree(shm->pages); | 44 | kfree(shm->pages); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | if (shm->ctx) | 47 | teedev_ctx_put(shm->ctx); |
| 48 | teedev_ctx_put(shm->ctx); | ||
| 49 | 48 | ||
| 50 | kfree(shm); | 49 | kfree(shm); |
| 51 | 50 | ||
| @@ -77,7 +76,7 @@ static int tee_shm_op_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) · 25 unmodified lines | |||
| 77 | size_t size = vma->vm_end - vma->vm_start; | 76 | size_t size = vma->vm_end - vma->vm_start; |
| 78 | 77 | ||
| 79 | /* Refuse sharing shared memory provided by application */ | 78 | /* Refuse sharing shared memory provided by application */ |
| 80 | if (shm->flags & TEE_SHM_REGISTER) | 79 | if (shm->flags & TEE_SHM_USER_MAPPED) |
| 81 | return -EINVAL; | 80 | return -EINVAL; |
| 82 | 81 | ||
| 83 | return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, | 82 | return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT, |
| @@ -91,20 +90,14 @@ static const struct dma_buf_ops tee_shm_dma_buf_ops = { · 7 unmodified lines | |||
| 91 | .mmap = tee_shm_op_mmap, | 90 | .mmap = tee_shm_op_mmap, |
| 92 | }; | 91 | }; |
| 93 | 92 | ||
| 94 | static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, | 93 | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) |
| 95 | struct tee_device *teedev, | ||
| 96 | size_t size, u32 flags) | ||
| 97 | { | 94 | { |
| 95 | struct tee_device *teedev = ctx->teedev; | ||
| 98 | struct tee_shm_pool_mgr *poolm = NULL; | 96 | struct tee_shm_pool_mgr *poolm = NULL; |
| 99 | struct tee_shm *shm; | 97 | struct tee_shm *shm; |
| 100 | void *ret; | 98 | void *ret; |
| 101 | int rc; | 99 | int rc; |
| 102 | 100 | ||
| 103 | if (ctx && ctx->teedev != teedev) { | ||
| 104 | dev_err(teedev->dev.parent, "ctx and teedev mismatch\n"); | ||
| 105 | return ERR_PTR(-EINVAL); | ||
| 106 | } | ||
| 107 | |||
| 108 | if (!(flags & TEE_SHM_MAPPED)) { | 101 | if (!(flags & TEE_SHM_MAPPED)) { |
| 109 | dev_err(teedev->dev.parent, | 102 | dev_err(teedev->dev.parent, |
| 110 | "only mapped allocations supported\n"); | 103 | "only mapped allocations supported\n"); |
| @@ -132,7 +125,6 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, · 21 unmodified lines | |||
| 132 | } | 125 | } |
| 133 | 126 | ||
| 134 | shm->flags = flags | TEE_SHM_POOL; | 127 | shm->flags = flags | TEE_SHM_POOL; |
| 135 | shm->teedev = teedev; | ||
| 136 | shm->ctx = ctx; | 128 | shm->ctx = ctx; |
| 137 | if (flags & TEE_SHM_DMA_BUF) | 129 | if (flags & TEE_SHM_DMA_BUF) |
| 138 | poolm = teedev->pool->dma_buf_mgr; | 130 | poolm = teedev->pool->dma_buf_mgr; |
| @@ -145,17 +137,18 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, · 6 unmodified lines | |||
| 145 | goto err_kfree; | 137 | goto err_kfree; |
| 146 | } | 138 | } |
| 147 | 139 | ||
| 148 | mutex_lock(&teedev->mutex); | ||
| 149 | shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); | ||
| 150 | mutex_unlock(&teedev->mutex); | ||
| 151 | if (shm->id < 0) { | ||
| 152 | ret = ERR_PTR(shm->id); | ||
| 153 | goto err_pool_free; | ||
| 154 | } | ||
| 155 | 140 | ||
| 156 | if (flags & TEE_SHM_DMA_BUF) { | 141 | if (flags & TEE_SHM_DMA_BUF) { |
| 157 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); | 142 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); |
| 158 | 143 | ||
| 144 | mutex_lock(&teedev->mutex); | ||
| 145 | shm->id = idr_alloc(&teedev->idr, shm, 1, 0, GFP_KERNEL); | ||
| 146 | mutex_unlock(&teedev->mutex); | ||
| 147 | if (shm->id < 0) { | ||
| 148 | ret = ERR_PTR(shm->id); | ||
| 149 | goto err_pool_free; | ||
| 150 | } | ||
| 151 | |||
| 159 | exp_info.ops = &tee_shm_dma_buf_ops; | 152 | exp_info.ops = &tee_shm_dma_buf_ops; |
| 160 | exp_info.size = shm->size; | 153 | exp_info.size = shm->size; |
| 161 | exp_info.flags = O_RDWR; | 154 | exp_info.flags = O_RDWR; |
| @@ -168,18 +161,16 @@ static struct tee_shm *__tee_shm_alloc(struct tee_context *ctx, · 6 unmodified lines | |||
| 168 | } | 161 | } |
| 169 | } | 162 | } |
| 170 | 163 | ||
| 171 | if (ctx) { | 164 | if (ctx) |
| 172 | teedev_ctx_get(ctx); | 165 | teedev_ctx_get(ctx); |
| 173 | mutex_lock(&teedev->mutex); | ||
| 174 | list_add_tail(&shm->link, &ctx->list_shm); | ||
| 175 | mutex_unlock(&teedev->mutex); | ||
| 176 | } | ||
| 177 | 166 | ||
| 178 | return shm; | 167 | return shm; |
| 179 | err_rem: | 168 | err_rem: |
| 180 | mutex_lock(&teedev->mutex); | 169 | if (flags & TEE_SHM_DMA_BUF) { |
| 181 | idr_remove(&teedev->idr, shm->id); | 170 | mutex_lock(&teedev->mutex); |
| 182 | mutex_unlock(&teedev->mutex); | 171 | idr_remove(&teedev->idr, shm->id); |
| 172 | mutex_unlock(&teedev->mutex); | ||
| 173 | } | ||
| 183 | err_pool_free: | 174 | err_pool_free: |
| 184 | poolm->ops->free(poolm, shm); | 175 | poolm->ops->free(poolm, shm); |
| 185 | err_kfree: | 176 | err_kfree: |
| @@ -188,31 +179,8 @@ err_dev_put: · 2 unmodified lines | |||
| 188 | tee_device_put(teedev); | 179 | tee_device_put(teedev); |
| 189 | return ret; | 180 | return ret; |
| 190 | } | 181 | } |
| 191 | |||
| 192 | /** | ||
| 193 | * tee_shm_alloc() - Allocate shared memory | ||
| 194 | * @ctx: Context that allocates the shared memory | ||
| 195 | * @size: Requested size of shared memory | ||
| 196 | * @flags: Flags setting properties for the requested shared memory. | ||
| 197 | * | ||
| 198 | * Memory allocated as global shared memory is automatically freed when the | ||
| 199 | * TEE file pointer is closed. The @flags field uses the bits defined by | ||
| 200 | * TEE_SHM_* in <linux/tee_drv.h>. TEE_SHM_MAPPED must currently always be | ||
| 201 | * set. If TEE_SHM_DMA_BUF global shared memory will be allocated and | ||
| 202 | * associated with a dma-buf handle, else driver private memory. | ||
| 203 | */ | ||
| 204 | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags) | ||
| 205 | { | ||
| 206 | return __tee_shm_alloc(ctx, ctx->teedev, size, flags); | ||
| 207 | } | ||
| 208 | EXPORT_SYMBOL_GPL(tee_shm_alloc); | 182 | EXPORT_SYMBOL_GPL(tee_shm_alloc); |
| 209 | 183 | ||
| 210 | struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size) | ||
| 211 | { | ||
| 212 | return __tee_shm_alloc(NULL, teedev, size, TEE_SHM_MAPPED); | ||
| 213 | } | ||
| 214 | EXPORT_SYMBOL_GPL(tee_shm_priv_alloc); | ||
| 215 | |||
| 216 | struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, | 184 | struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, |
| 217 | size_t length, u32 flags) | 185 | size_t length, u32 flags) |
| 218 | { | 186 | { |
| @@ -245,7 +213,6 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, · 26 unmodified lines | |||
| 245 | } | 213 | } |
| 246 | 214 | ||
| 247 | shm->flags = flags | TEE_SHM_REGISTER; | 215 | shm->flags = flags | TEE_SHM_REGISTER; |
| 248 | shm->teedev = teedev; | ||
| 249 | shm->ctx = ctx; | 216 | shm->ctx = ctx; |
| 250 | shm->id = -1; | 217 | shm->id = -1; |
| 251 | addr = untagged_addr(addr); | 218 | addr = untagged_addr(addr); |
| @@ -301,10 +268,6 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, · 49 unmodified lines | |||
| 301 | } | 268 | } |
| 302 | } | 269 | } |
| 303 | 270 | ||
| 304 | mutex_lock(&teedev->mutex); | ||
| 305 | list_add_tail(&shm->link, &ctx->list_shm); | ||
| 306 | mutex_unlock(&teedev->mutex); | ||
| 307 | |||
| 308 | return shm; | 271 | return shm; |
| 309 | err: | 272 | err: |
| 310 | if (shm) { | 273 | if (shm) { |
| @@ -18,6 +18,10 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #define SYSC_DRA7_MCAN_ENAWAKEUP (1 << 4) | 19 | #define SYSC_DRA7_MCAN_ENAWAKEUP (1 << 4) |
| 20 | 20 | ||
| 21 | /* PRUSS sysc found on AM33xx/AM43xx/AM57xx */ | ||
| 22 | #define SYSC_PRUSS_SUB_MWAIT (1 << 5) | ||
| 23 | #define SYSC_PRUSS_STANDBY_INIT (1 << 4) | ||
| 24 | |||
| 21 | /* SYSCONFIG STANDBYMODE/MIDLEMODE/SIDLEMODE supported by hardware */ | 25 | /* SYSCONFIG STANDBYMODE/MIDLEMODE/SIDLEMODE supported by hardware */ |
| 22 | #define SYSC_IDLE_FORCE 0 | 26 | #define SYSC_IDLE_FORCE 0 |
| 23 | #define SYSC_IDLE_NO 1 | 27 | #define SYSC_IDLE_NO 1 |
| @@ -0,0 +1,32 @@ | |||
| 1 | /* SPDX-License-Identifier: (GPL-2.0+ or MIT) */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2019 Amlogic, Inc. | ||
| 4 | * Author: Jianxin Pan <jianxin.pan@amlogic.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef _DT_BINDINGS_MESON_A1_POWER_H | ||
| 8 | #define _DT_BINDINGS_MESON_A1_POWER_H | ||
| 9 | |||
| 10 | #define PWRC_DSPA_ID 8 | ||
| 11 | #define PWRC_DSPB_ID 9 | ||
| 12 | #define PWRC_UART_ID 10 | ||
| 13 | #define PWRC_DMC_ID 11 | ||
| 14 | #define PWRC_I2C_ID 12 | ||
| 15 | #define PWRC_PSRAM_ID 13 | ||
| 16 | #define PWRC_ACODEC_ID 14 | ||
| 17 | #define PWRC_AUDIO_ID 15 | ||
| 18 | #define PWRC_OTP_ID 16 | ||
| 19 | #define PWRC_DMA_ID 17 | ||
| 20 | #define PWRC_SD_EMMC_ID 18 | ||
| 21 | #define PWRC_RAMA_ID 19 | ||
| 22 | #define PWRC_RAMB_ID 20 | ||
| 23 | #define PWRC_IR_ID 21 | ||
| 24 | #define PWRC_SPICC_ID 22 | ||
| 25 | #define PWRC_SPIFC_ID 23 | ||
| 26 | #define PWRC_USB_ID 24 | ||
| 27 | #define PWRC_NIC_ID 25 | ||
| 28 | #define PWRC_PDMIN_ID 26 | ||
| 29 | #define PWRC_RSA_ID 27 | ||
| 30 | #define PWRC_MAX_ID 28 | ||
| 31 | |||
| 32 | #endif | ||
| @@ -25,7 +25,6 @@ enum imx_sc_rpc_svc { · 24 unmodified lines | |||
| 25 | IMX_SC_RPC_SVC_PAD = 6, | 25 | IMX_SC_RPC_SVC_PAD = 6, |
| 26 | IMX_SC_RPC_SVC_MISC = 7, | 26 | IMX_SC_RPC_SVC_MISC = 7, |
| 27 | IMX_SC_RPC_SVC_IRQ = 8, | 27 | IMX_SC_RPC_SVC_IRQ = 8, |
| 28 | IMX_SC_RPC_SVC_ABORT = 9 | ||
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| 31 | struct imx_sc_rpc_msg { | 30 | struct imx_sc_rpc_msg { |
| @@ -12,6 +12,8 @@ enum { · 11 unmodified lines | |||
| 12 | SM_EFUSE_WRITE, | 12 | SM_EFUSE_WRITE, |
| 13 | SM_EFUSE_USER_MAX, | 13 | SM_EFUSE_USER_MAX, |
| 14 | SM_GET_CHIP_ID, | 14 | SM_GET_CHIP_ID, |
| 15 | SM_A1_PWRC_SET, | ||
| 16 | SM_A1_PWRC_GET, | ||
| 15 | }; | 17 | }; |
| 16 | 18 | ||
| 17 | struct meson_sm_firmware; | 19 | struct meson_sm_firmware; |
| @@ -17,6 +17,7 @@ enum ti_sysc_module_type { · 16 unmodified lines | |||
| 17 | TI_SYSC_OMAP4_MCASP, | 17 | TI_SYSC_OMAP4_MCASP, |
| 18 | TI_SYSC_OMAP4_USB_HOST_FS, | 18 | TI_SYSC_OMAP4_USB_HOST_FS, |
| 19 | TI_SYSC_DRA7_MCAN, | 19 | TI_SYSC_DRA7_MCAN, |
| 20 | TI_SYSC_PRUSS, | ||
| 20 | }; | 21 | }; |
| 21 | 22 | ||
| 22 | struct ti_sysc_cookie { | 23 | struct ti_sysc_cookie { |
| @@ -49,6 +50,9 @@ struct sysc_regbits { · 26 unmodified lines | |||
| 49 | s8 emufree_shift; | 50 | s8 emufree_shift; |
| 50 | }; | 51 | }; |
| 51 | 52 | ||
| 53 | #define SYSC_MODULE_QUIRK_PRUSS BIT(24) | ||
| 54 | #define SYSC_MODULE_QUIRK_DSS_RESET BIT(23) | ||
| 55 | #define SYSC_MODULE_QUIRK_RTC_UNLOCK BIT(22) | ||
| 52 | #define SYSC_QUIRK_CLKDM_NOAUTO BIT(21) | 56 | #define SYSC_QUIRK_CLKDM_NOAUTO BIT(21) |
| 53 | #define SYSC_QUIRK_FORCE_MSTANDBY BIT(20) | 57 | #define SYSC_QUIRK_FORCE_MSTANDBY BIT(20) |
| 54 | #define SYSC_MODULE_QUIRK_AESS BIT(19) | 58 | #define SYSC_MODULE_QUIRK_AESS BIT(19) |
| @@ -141,6 +145,7 @@ struct clk; · 86 unmodified lines | |||
| 141 | 145 | ||
| 142 | struct ti_sysc_platform_data { | 146 | struct ti_sysc_platform_data { |
| 143 | struct of_dev_auxdata *auxdata; | 147 | struct of_dev_auxdata *auxdata; |
| 148 | bool (*soc_type_gp)(void); | ||
| 144 | int (*init_clockdomain)(struct device *dev, struct clk *fck, | 149 | int (*init_clockdomain)(struct device *dev, struct clk *fck, |
| 145 | struct clk *ick, struct ti_sysc_cookie *cookie); | 150 | struct clk *ick, struct ti_sysc_cookie *cookie); |
| 146 | void (*clkdm_deny_idle)(struct device *dev, | 151 | void (*clkdm_deny_idle)(struct device *dev, |
| @@ -85,6 +85,7 @@ struct apr_device { · 84 unmodified lines | |||
| 85 | uint16_t domain_id; | 85 | uint16_t domain_id; |
| 86 | uint32_t version; | 86 | uint32_t version; |
| 87 | char name[APR_NAME_SIZE]; | 87 | char name[APR_NAME_SIZE]; |
| 88 | const char *service_path; | ||
| 88 | spinlock_t lock; | 89 | spinlock_t lock; |
| 89 | struct list_head node; | 90 | struct list_head node; |
| 90 | }; | 91 | }; |
| @@ -0,0 +1,29 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #ifndef __QCOM_PDR_HELPER__ | ||
| 3 | #define __QCOM_PDR_HELPER__ | ||
| 4 | |||
| 5 | #include <linux/soc/qcom/qmi.h> | ||
| 6 | |||
| 7 | #define SERVREG_NAME_LENGTH 64 | ||
| 8 | |||
| 9 | struct pdr_service; | ||
| 10 | struct pdr_handle; | ||
| 11 | |||
| 12 | enum servreg_service_state { | ||
| 13 | SERVREG_LOCATOR_ERR = 0x1, | ||
| 14 | SERVREG_SERVICE_STATE_DOWN = 0x0FFFFFFF, | ||
| 15 | SERVREG_SERVICE_STATE_UP = 0x1FFFFFFF, | ||
| 16 | SERVREG_SERVICE_STATE_EARLY_DOWN = 0x2FFFFFFF, | ||
| 17 | SERVREG_SERVICE_STATE_UNINIT = 0x7FFFFFFF, | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct pdr_handle *pdr_handle_alloc(void (*status)(int state, | ||
| 21 | char *service_path, | ||
| 22 | void *priv), void *priv); | ||
| 23 | struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, | ||
| 24 | const char *service_name, | ||
| 25 | const char *service_path); | ||
| 26 | int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds); | ||
| 27 | void pdr_handle_release(struct pdr_handle *pdr); | ||
| 28 | |||
| 29 | #endif | ||
| @@ -88,6 +88,7 @@ struct qmi_elem_info { · 87 unmodified lines | |||
| 88 | #define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 5 | 88 | #define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 5 |
| 89 | #define QMI_ERR_INVALID_ID_V01 41 | 89 | #define QMI_ERR_INVALID_ID_V01 41 |
| 90 | #define QMI_ERR_ENCODING_V01 58 | 90 | #define QMI_ERR_ENCODING_V01 58 |
| 91 | #define QMI_ERR_DISABLED_V01 69 | ||
| 91 | #define QMI_ERR_INCOMPATIBLE_STATE_V01 90 | 92 | #define QMI_ERR_INCOMPATIBLE_STATE_V01 90 |
| 92 | #define QMI_ERR_NOT_SUPPORTED_V01 94 | 93 | #define QMI_ERR_NOT_SUPPORTED_V01 94 |
| 93 | 94 | ||
| @@ -49,7 +49,6 @@ struct tee_shm_pool; · 48 unmodified lines | |||
| 49 | */ | 49 | */ |
| 50 | struct tee_context { | 50 | struct tee_context { |
| 51 | struct tee_device *teedev; | 51 | struct tee_device *teedev; |
| 52 | struct list_head list_shm; | ||
| 53 | void *data; | 52 | void *data; |
| 54 | struct kref refcount; | 53 | struct kref refcount; |
| 55 | bool releasing; | 54 | bool releasing; |
| @@ -168,9 +167,7 @@ void tee_device_unregister(struct tee_device *teedev); · 112 unmodified lines | |||
| 168 | 167 | ||
| 169 | /** | 168 | /** |
| 170 | * struct tee_shm - shared memory object | 169 | * struct tee_shm - shared memory object |
| 171 | * @teedev: device used to allocate the object | 170 | * @ctx: context using the object |
| 172 | * @ctx: context using the object, if NULL the context is gone | ||
| 173 | * @link link element | ||
| 174 | * @paddr: physical address of the shared memory | 171 | * @paddr: physical address of the shared memory |
| 175 | * @kaddr: virtual address of the shared memory | 172 | * @kaddr: virtual address of the shared memory |
| 176 | * @size: size of shared memory | 173 | * @size: size of shared memory |
| @@ -185,9 +182,7 @@ void tee_device_unregister(struct tee_device *teedev); · 8 unmodified lines | |||
| 185 | * subsystem and from drivers that implements their own shm pool manager. | 182 | * subsystem and from drivers that implements their own shm pool manager. |
| 186 | */ | 183 | */ |
| 187 | struct tee_shm { | 184 | struct tee_shm { |
| 188 | struct tee_device *teedev; | ||
| 189 | struct tee_context *ctx; | 185 | struct tee_context *ctx; |
| 190 | struct list_head link; | ||
| 191 | phys_addr_t paddr; | 186 | phys_addr_t paddr; |
| 192 | void *kaddr; | 187 | void *kaddr; |
| 193 | size_t size; | 188 | size_t size; |
| @@ -318,18 +313,6 @@ void *tee_get_drvdata(struct tee_device *teedev); · 124 unmodified lines | |||
| 318 | */ | 313 | */ |
| 319 | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags); | 314 | struct tee_shm *tee_shm_alloc(struct tee_context *ctx, size_t size, u32 flags); |
| 320 | 315 | ||
| 321 | /** | ||
| 322 | * tee_shm_priv_alloc() - Allocate shared memory privately | ||
| 323 | * @dev: Device that allocates the shared memory | ||
| 324 | * @size: Requested size of shared memory | ||
| 325 | * | ||
| 326 | * Allocates shared memory buffer that is not associated with any client | ||
| 327 | * context. Such buffers are owned by TEE driver and used for internal calls. | ||
| 328 | * | ||
| 329 | * @returns a pointer to 'struct tee_shm' | ||
| 330 | */ | ||
| 331 | struct tee_shm *tee_shm_priv_alloc(struct tee_device *teedev, size_t size); | ||
| 332 | |||
| 333 | /** | 316 | /** |
| 334 | * tee_shm_register() - Register shared memory buffer | 317 | * tee_shm_register() - Register shared memory buffer |
| 335 | * @ctx: Context that registers the shared memory | 318 | * @ctx: Context that registers the shared memory |
| @@ -1,7 +1,7 @@ | |||
| 1 | /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ | 1 | /* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ |
| 2 | /* | 2 | /* |
| 3 | * Copyright 2014-2016 Freescale Semiconductor Inc. | 3 | * Copyright 2014-2016 Freescale Semiconductor Inc. |
| 4 | * Copyright NXP | 4 | * Copyright 2017-2019 NXP |
| 5 | * | 5 | * |
| 6 | */ | 6 | */ |
| 7 | #ifndef __FSL_DPAA2_IO_H | 7 | #ifndef __FSL_DPAA2_IO_H |
| @@ -109,6 +109,10 @@ int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, · 101 unmodified lines | |||
| 109 | 109 | ||
| 110 | int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid, | 110 | int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid, |
| 111 | const struct dpaa2_fd *fd); | 111 | const struct dpaa2_fd *fd); |
| 112 | int dpaa2_io_service_enqueue_multiple_fq(struct dpaa2_io *d, u32 fqid, | ||
| 113 | const struct dpaa2_fd *fd, int number_of_frame); | ||
| 114 | int dpaa2_io_service_enqueue_multiple_desc_fq(struct dpaa2_io *d, u32 *fqid, | ||
| 115 | const struct dpaa2_fd *fd, int number_of_frame); | ||
| 112 | int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, | 116 | int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, |
| 113 | u16 qdbin, const struct dpaa2_fd *fd); | 117 | u16 qdbin, const struct dpaa2_fd *fd); |
| 114 | int dpaa2_io_service_release(struct dpaa2_io *d, u16 bpid, | 118 | int dpaa2_io_service_release(struct dpaa2_io *d, u16 bpid, |
| @@ -178,10 +178,10 @@ struct ucc_fast_info { · 177 unmodified lines | |||
| 178 | struct ucc_fast_private { | 178 | struct ucc_fast_private { |
| 179 | struct ucc_fast_info *uf_info; | 179 | struct ucc_fast_info *uf_info; |
| 180 | struct ucc_fast __iomem *uf_regs; /* a pointer to the UCC regs. */ | 180 | struct ucc_fast __iomem *uf_regs; /* a pointer to the UCC regs. */ |
| 181 | u32 __iomem *p_ucce; /* a pointer to the event register in memory. */ | 181 | __be32 __iomem *p_ucce; /* a pointer to the event register in memory. */ |
| 182 | u32 __iomem *p_uccm; /* a pointer to the mask register in memory. */ | 182 | __be32 __iomem *p_uccm; /* a pointer to the mask register in memory. */ |
| 183 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | 183 | #ifdef CONFIG_UGETH_TX_ON_DEMAND |
| 184 | u16 __iomem *p_utodr; /* pointer to the transmit on demand register */ | 184 | __be16 __iomem *p_utodr;/* pointer to the transmit on demand register */ |
| 185 | #endif | 185 | #endif |
| 186 | int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ | 186 | int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ |
| 187 | int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ | 187 | int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ |
| @@ -184,7 +184,7 @@ struct ucc_slow_info { · 183 unmodified lines | |||
| 184 | struct ucc_slow_private { | 184 | struct ucc_slow_private { |
| 185 | struct ucc_slow_info *us_info; | 185 | struct ucc_slow_info *us_info; |
| 186 | struct ucc_slow __iomem *us_regs; /* Ptr to memory map of UCC regs */ | 186 | struct ucc_slow __iomem *us_regs; /* Ptr to memory map of UCC regs */ |
| 187 | struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */ | 187 | struct ucc_slow_pram __iomem *us_pram; /* a pointer to the parameter RAM */ |
| 188 | s32 us_pram_offset; | 188 | s32 us_pram_offset; |
| 189 | int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ | 189 | int enabled_tx; /* Whether channel is enabled for Tx (ENT) */ |
| 190 | int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ | 190 | int enabled_rx; /* Whether channel is enabled for Rx (ENR) */ |
| @@ -196,13 +196,12 @@ struct ucc_slow_private { · 5 unmodified lines | |||
| 196 | and length for first BD in a frame */ | 196 | and length for first BD in a frame */ |
| 197 | s32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */ | 197 | s32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */ |
| 198 | s32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */ | 198 | s32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */ |
| 199 | struct qe_bd *confBd; /* next BD for confirm after Tx */ | 199 | struct qe_bd __iomem *confBd; /* next BD for confirm after Tx */ |
| 200 | struct qe_bd *tx_bd; /* next BD for new Tx request */ | 200 | struct qe_bd __iomem *tx_bd; /* next BD for new Tx request */ |
| 201 | struct qe_bd *rx_bd; /* next BD to collect after Rx */ | 201 | struct qe_bd __iomem *rx_bd; /* next BD to collect after Rx */ |
| 202 | void *p_rx_frame; /* accumulating receive frame */ | 202 | void *p_rx_frame; /* accumulating receive frame */ |
| 203 | u16 *p_ucce; /* a pointer to the event register in memory. | 203 | __be16 __iomem *p_ucce; /* a pointer to the event register in memory */ |
| 204 | */ | 204 | __be16 __iomem *p_uccm; /* a pointer to the mask register in memory */ |
| 205 | u16 *p_uccm; /* a pointer to the mask register in memory */ | ||
| 206 | u16 saved_uccm; /* a saved mask for the RX Interrupt bits */ | 205 | u16 saved_uccm; /* a saved mask for the RX Interrupt bits */ |
| 207 | #ifdef STATISTICS | 206 | #ifdef STATISTICS |
| 208 | u32 tx_frames; /* Transmitted frames counters */ | 207 | u32 tx_frames; /* Transmitted frames counters */ |
| @@ -20,8 +20,6 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state, · 19 unmodified lines | |||
| 20 | int rpmh_write_batch(const struct device *dev, enum rpmh_state state, | 20 | int rpmh_write_batch(const struct device *dev, enum rpmh_state state, |
| 21 | const struct tcs_cmd *cmd, u32 *n); | 21 | const struct tcs_cmd *cmd, u32 *n); |
| 22 | 22 | ||
| 23 | int rpmh_flush(const struct device *dev); | ||
| 24 | |||
| 25 | int rpmh_invalidate(const struct device *dev); | 23 | int rpmh_invalidate(const struct device *dev); |
| 26 | 24 | ||
| 27 | #else | 25 | #else |
| @@ -40,9 +38,6 @@ static inline int rpmh_write_batch(const struct device *dev, · 12 unmodified lines | |||
| 40 | const struct tcs_cmd *cmd, u32 *n) | 38 | const struct tcs_cmd *cmd, u32 *n) |
| 41 | { return -ENODEV; } | 39 | { return -ENODEV; } |
| 42 | 40 | ||
| 43 | static inline int rpmh_flush(const struct device *dev) | ||
| 44 | { return -ENODEV; } | ||
| 45 | |||
| 46 | static inline int rpmh_invalidate(const struct device *dev) | 41 | static inline int rpmh_invalidate(const struct device *dev) |
| 47 | { return -ENODEV; } | 42 | { return -ENODEV; } |
| 48 | 43 | ||