Qualcomm driver updates for v6.7

This introduces partial support for the Qualcomm Secure Execution
 Environment SCM interface, and uses this to implement EFI variable
 access on the Windows On Snapdragon devices (for now).
 
 The 32/64-bit calling convention detector of the SCM interface is
 updated to not choose 64-bit convention when Linux is 32-bit. The
 "extern" specifier is dropped from the interface include file.
 
 The LLCC driver gains support for carrying configuration for multiple
 different system/DDR configurations for a given platform, and selecting
 between them. Support for Q[DR]U1000 is added to the driver.
 
 All exported symbols are transitioned to EXPORT_SYMBOL_GPL().
 
 The platform_drivers in the Qualcomm SoC are transitioned to the
 void-returning remove_new implementation.
 
 The rmtfs memory driver gains support for leaving guard pages around the
 used area, to avoid issues if the allocation happens to be placed
 adjacent to another protected memory region.
 
 The socinfo driver gains knowledge about IPQ8174, QCM6490, SM7150P and
 various PMICs used together with SM8550.
 -----BEGIN PGP SIGNATURE-----
 
 iQJJBAABCAAzFiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAmUsTdwVHGFuZGVyc3Nv
 bkBrZXJuZWwub3JnAAoJEAsfOT8Nma3FffsQAMcY5NKBZqbQu5wNr2zPnKW5m/30
 lYi4bW42mlY6Mo3h97LLxjGM9bqsmPasfAxv/84viN0JYxrSVye/zNtD35qTQBtu
 t8O8vdOaOYXIc8dwqC16Fl0kI5pm9tl7p5SJmGAUZBvIGUIGngy3gZOYM+HzyMQr
 UXFO6dO0tQvjowd1t0xE51UNm4J79Vm8HjtuR1pc4i+fZhsy5XhZYq9e4531Yc7o
 lNacBugjXhurw/rz0odNuRzKn+He+7KQR/hSNv8B2MbH0ZUP+k4VUaRSD9TZyBgC
 cOahbCfVLkGwepPFGuaaJUUgo8/aa4HiAbdyOrNL2ozYkoLv/PbRrLF0R9KgXK5v
 LPXpqXt97+rWPnq2iPrfZlo4LAj6JVSCUCxIRZFcWyDFv+wHsYuRbO64s1+MC7+M
 CPpvup31PLGCeR9Joo/WTt9iAUPJ4BY9v4mkjIdmJF371WRryP4um5Ln6xMC+fIe
 U/Ss8mPNpSM+guDo8LbdCGAcxWTDk8TOXxa/888y/4Q5Mg97nn0hY2KK4JBmJ7I3
 Thd0n9vXjM3oOwPGLC7Y2zj9ZQI5k7JKn331yPS4Hb20SKGEztlaJp4B1DdA5/ul
 4BUoh3HWV7dB4l+felrAmPAzAUXvyfGrDBJhXe2dabRJjMhouQ6Wudn3OlC4VP/l
 fjszjVvPFt7CE30C
 =B1Kn
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmUv9yoACgkQYKtH/8kJ
 UifTOQ/+NUj5Y/sAZfMLY3Q3e8s2nsKZLHHUCH7O/DOR6ILc5DZcTI5a23kfIA9V
 VVluTEnRUzbSHCb3WPW3Yfgy5HpZoaLgXWXGgCsRVKRIODN745TOm2Hn/dFZF0Z7
 Fso0oPplGKrvuxSlaxg+1fbJ7c5r8kE/TDu+ok0eiZGvzwfnVas4bB+27thdH/le
 tY/wS9BhHmBrs6k7gqCfEFWF7M6kS29FOPILIlAfxgUevgSIvAUMBH/KUAGw1Qo/
 UNd372TwXkdw0pG2KOx8xR4iKFBfWX4PbHBtBbUZzAnqerDnNrh7p0qTlhfKXOpb
 jQWx3eqQIwFbbWZ39DxiLE8/h5ig3jF29u1s/vAG2Zb5o5cYwiRM7OjWW8Q8Ha1E
 ha2NSWMEaNniegnMeoy1VTN8uSYY+dUseKmLmP5vCobmYVKuX96iQx5pNBYhsrwN
 YOlkOkF1fXINFqSD5v2N4s4AdGx634GgP7azkjm6fGS+hlwKgWNzwH4HHgXNx/u/
 IPRPw7U/hji2R++oNPtEOlNHoHWM6Zx0ema38qGTC69uAFHETxbFUmOBaX6q/7Ot
 AwpP25YozehwDoUVZRwR6CpHcVbKDl4oJhWaruflkxC+6YFTGYS2hPFiF6zbnQw9
 u36QDkgNzhBG2LINlmqCAAoGWmC+mqwsqYN/DyKsUUSVEODyUng=
 =7XXT
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-for-6.7' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/drivers

Qualcomm driver updates for v6.7

This introduces partial support for the Qualcomm Secure Execution
Environment SCM interface, and uses this to implement EFI variable
access on the Windows On Snapdragon devices (for now).

The 32/64-bit calling convention detector of the SCM interface is
updated to not choose 64-bit convention when Linux is 32-bit. The
"extern" specifier is dropped from the interface include file.

The LLCC driver gains support for carrying configuration for multiple
different system/DDR configurations for a given platform, and selecting
between them. Support for Q[DR]U1000 is added to the driver.

All exported symbols are transitioned to EXPORT_SYMBOL_GPL().

The platform_drivers in the Qualcomm SoC are transitioned to the
void-returning remove_new implementation.

The rmtfs memory driver gains support for leaving guard pages around the
used area, to avoid issues if the allocation happens to be placed
adjacent to another protected memory region.

The socinfo driver gains knowledge about IPQ8174, QCM6490, SM7150P and
various PMICs used together with SM8550.

* tag 'qcom-drivers-for-6.7' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (44 commits)
  soc: qcom: socinfo: Convert to platform remove callback returning void
  soc: qcom: smsm: Convert to platform remove callback returning void
  soc: qcom: smp2p: Convert to platform remove callback returning void
  soc: qcom: smem: Convert to platform remove callback returning void
  soc: qcom: rmtfs_mem: Convert to platform remove callback returning void
  soc: qcom: qcom_stats: Convert to platform remove callback returning void
  soc: qcom: qcom_gsbi: Convert to platform remove callback returning void
  soc: qcom: qcom_aoss: Convert to platform remove callback returning void
  soc: qcom: pmic_glink: Convert to platform remove callback returning void
  soc: qcom: ocmem: Convert to platform remove callback returning void
  soc: qcom: llcc-qcom: Convert to platform remove callback returning void
  soc: qcom: icc-bwmon: Convert to platform remove callback returning void
  firmware: qcom_scm: use 64-bit calling convention only when client is 64-bit
  soc: qcom: llcc: Handle a second device without data corruption
  soc: qcom: Switch to EXPORT_SYMBOL_GPL()
  soc: qcom: smem: Annotate struct qcom_smem with __counted_by
  soc: qcom: rmtfs: Support discarding guard pages
  dt-bindings: reserved-memory: rmtfs: Allow guard pages
  dt-bindings: firmware: qcom,scm: document IPQ5018 compatible
  firmware: qcom_scm: disable SDI if required
  ...

Link: https://lore.kernel.org/r/20231015204014.855672-1-andersson@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2023-10-18 17:17:56 +02:00
commit 57e06f8c1f
40 changed files with 2084 additions and 255 deletions

View File

@ -20,6 +20,7 @@ description: |
properties:
compatible:
enum:
- qcom,qdu1000-llcc
- qcom,sc7180-llcc
- qcom,sc7280-llcc
- qcom,sc8180x-llcc
@ -44,6 +45,14 @@ properties:
interrupts:
maxItems: 1
nvmem-cells:
items:
- description: Reference to an nvmem node for multi channel DDR
nvmem-cell-names:
items:
- const: multi-chan-ddr
required:
- compatible
- reg
@ -92,6 +101,7 @@ allOf:
compatible:
contains:
enum:
- qcom,qdu1000-llcc
- qcom,sc8180x-llcc
- qcom,sc8280xp-llcc
then:

View File

@ -24,6 +24,7 @@ properties:
- qcom,scm-apq8064
- qcom,scm-apq8084
- qcom,scm-ipq4019
- qcom,scm-ipq5018
- qcom,scm-ipq5332
- qcom,scm-ipq6018
- qcom,scm-ipq806x
@ -56,6 +57,7 @@ properties:
- qcom,scm-sm6125
- qcom,scm-sm6350
- qcom,scm-sm6375
- qcom,scm-sm7150
- qcom,scm-sm8150
- qcom,scm-sm8250
- qcom,scm-sm8350
@ -89,6 +91,14 @@ properties:
protocol to handle sleeping SCM calls.
maxItems: 1
qcom,sdi-enabled:
description:
Indicates that the SDI (Secure Debug Image) has been enabled by TZ
by default and it needs to be disabled.
If not disabled WDT assertion or reboot will cause the board to hang
in the debug mode.
type: boolean
qcom,dload-mode:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:

View File

@ -26,6 +26,17 @@ properties:
description: >
identifier of the client to use this region for buffers
qcom,use-guard-pages:
type: boolean
description: >
Indicates that the firmware, or hardware, does not gracefully handle
memory protection of this region when placed adjacent to other protected
memory regions, and that padding around the used portion of the memory
region is necessary.
When this is set, the first and last page should be left unused, and the
effective size of the region will thereby shrink with two pages.
qcom,vmid:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: >

View File

@ -52,6 +52,8 @@ properties:
iommus:
maxItems: 1
dma-coherent: true
required:
- compatible
- reg

View File

@ -17801,6 +17801,18 @@ S: Maintained
F: Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
F: drivers/mtd/nand/raw/qcom_nandc.c
QUALCOMM QSEECOM DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/firmware/qcom_qseecom.c
QUALCOMM QSEECOM UEFISECAPP DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/firmware/qcom_qseecom_uefisecapp.c
QUALCOMM RMNET DRIVER
M: Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
M: Sean Tranchetti <quic_stranche@quicinc.com>

View File

@ -226,6 +226,39 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
Say Y here to enable "download mode" by default.
config QCOM_QSEECOM
bool "Qualcomm QSEECOM interface driver"
depends on QCOM_SCM=y
select AUXILIARY_BUS
help
Various Qualcomm SoCs have a Secure Execution Environment (SEE) running
in the Trust Zone. This module provides an interface to that via the
QSEECOM mechanism, using SCM calls.
The QSEECOM interface allows, among other things, access to applications
running in the SEE. An example of such an application is 'uefisecapp',
which is required to access UEFI variables on certain systems. If
selected, the interface will also attempt to detect and register client
devices for supported applications.
Select Y here to enable the QSEECOM interface driver.
config QCOM_QSEECOM_UEFISECAPP
bool "Qualcomm SEE UEFI Secure App client driver"
depends on QCOM_QSEECOM
depends on EFI
help
Various Qualcomm SoCs do not allow direct access to EFI variables.
Instead, these need to be accessed via the UEFI Secure Application
(uefisecapp), residing in the Secure Execution Environment (SEE).
This module provides a client driver for uefisecapp, installing efivar
operations to allow the kernel accessing EFI variables, and via that also
provide user-space with access to EFI variables via efivarfs.
Select Y here to provide access to EFI variables on the aforementioned
platforms.
config SYSFB
bool
select BOOT_VESA_SUPPORT

View File

@ -20,6 +20,8 @@ obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
obj-$(CONFIG_SYSFB) += sysfb.o
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o

View File

@ -0,0 +1,120 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
* Responsible for setting up and managing QSEECOM client devices.
*
* Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/firmware/qcom/qcom_qseecom.h>
#include <linux/firmware/qcom/qcom_scm.h>
struct qseecom_app_desc {
const char *app_name;
const char *dev_name;
};
static void qseecom_client_release(struct device *dev)
{
struct qseecom_client *client;
client = container_of(dev, struct qseecom_client, aux_dev.dev);
kfree(client);
}
static void qseecom_client_remove(void *data)
{
struct qseecom_client *client = data;
auxiliary_device_delete(&client->aux_dev);
auxiliary_device_uninit(&client->aux_dev);
}
static int qseecom_client_register(struct platform_device *qseecom_dev,
const struct qseecom_app_desc *desc)
{
struct qseecom_client *client;
u32 app_id;
int ret;
/* Try to find the app ID, skip device if not found */
ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id);
if (ret)
return ret == -ENOENT ? 0 : ret;
dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name);
/* Allocate and set-up the client device */
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;
client->aux_dev.name = desc->dev_name;
client->aux_dev.dev.parent = &qseecom_dev->dev;
client->aux_dev.dev.release = qseecom_client_release;
client->app_id = app_id;
ret = auxiliary_device_init(&client->aux_dev);
if (ret) {
kfree(client);
return ret;
}
ret = auxiliary_device_add(&client->aux_dev);
if (ret) {
auxiliary_device_uninit(&client->aux_dev);
return ret;
}
ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client);
if (ret)
return ret;
return 0;
}
/*
* List of supported applications. One client device will be created per entry,
* assuming the app has already been loaded (usually by firmware bootloaders)
* and its ID can be queried successfully.
*/
static const struct qseecom_app_desc qcom_qseecom_apps[] = {
{ "qcom.tz.uefisecapp", "uefisecapp" },
};
static int qcom_qseecom_probe(struct platform_device *qseecom_dev)
{
int ret;
int i;
/* Set up client devices for each base application */
for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) {
ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]);
if (ret)
return ret;
}
return 0;
}
static struct platform_driver qcom_qseecom_driver = {
.driver = {
.name = "qcom_qseecom",
},
.probe = qcom_qseecom_probe,
};
static int __init qcom_qseecom_init(void)
{
return platform_driver_register(&qcom_qseecom_driver);
}
subsys_initcall(qcom_qseecom_init);
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,871 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp).
* Provides access to UEFI variables on platforms where they are secured by the
* aforementioned Secure Execution Environment (SEE) application.
*
* Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/efi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/ucs2_string.h>
#include <linux/firmware/qcom/qcom_qseecom.h>
/* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */
/* Maximum length of name string with null-terminator */
#define QSEE_MAX_NAME_LEN 1024
#define QSEE_CMD_UEFI(x) (0x8000 | (x))
#define QSEE_CMD_UEFI_GET_VARIABLE QSEE_CMD_UEFI(0)
#define QSEE_CMD_UEFI_SET_VARIABLE QSEE_CMD_UEFI(1)
#define QSEE_CMD_UEFI_GET_NEXT_VARIABLE QSEE_CMD_UEFI(2)
#define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO QSEE_CMD_UEFI(3)
/**
* struct qsee_req_uefi_get_variable - Request for GetVariable command.
* @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE.
* @length: Length of the request in bytes, including this struct and any
* parameters (name, GUID) stored after it as well as any padding
* thereof for alignment.
* @name_offset: Offset from the start of this struct to where the variable
* name is stored (as utf-16 string), in bytes.
* @name_size: Size of the name parameter in bytes, including null-terminator.
* @guid_offset: Offset from the start of this struct to where the GUID
* parameter is stored, in bytes.
* @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
* @data_size: Size of the output buffer, in bytes.
*/
struct qsee_req_uefi_get_variable {
u32 command_id;
u32 length;
u32 name_offset;
u32 name_size;
u32 guid_offset;
u32 guid_size;
u32 data_size;
} __packed;
/**
* struct qsee_rsp_uefi_get_variable - Response for GetVariable command.
* @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE.
* @length: Length of the response in bytes, including this struct and the
* returned data.
* @status: Status of this command.
* @attributes: EFI variable attributes.
* @data_offset: Offset from the start of this struct to where the data is
* stored, in bytes.
* @data_size: Size of the returned data, in bytes. In case status indicates
* that the buffer is too small, this will be the size required
* to store the EFI variable data.
*/
struct qsee_rsp_uefi_get_variable {
u32 command_id;
u32 length;
u32 status;
u32 attributes;
u32 data_offset;
u32 data_size;
} __packed;
/**
* struct qsee_req_uefi_set_variable - Request for the SetVariable command.
* @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE.
* @length: Length of the request in bytes, including this struct and any
* parameters (name, GUID, data) stored after it as well as any
* padding thereof required for alignment.
* @name_offset: Offset from the start of this struct to where the variable
* name is stored (as utf-16 string), in bytes.
* @name_size: Size of the name parameter in bytes, including null-terminator.
* @guid_offset: Offset from the start of this struct to where the GUID
* parameter is stored, in bytes.
* @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
* @attributes: The EFI variable attributes to set for this variable.
* @data_offset: Offset from the start of this struct to where the EFI variable
* data is stored, in bytes.
* @data_size: Size of EFI variable data, in bytes.
*
*/
struct qsee_req_uefi_set_variable {
u32 command_id;
u32 length;
u32 name_offset;
u32 name_size;
u32 guid_offset;
u32 guid_size;
u32 attributes;
u32 data_offset;
u32 data_size;
} __packed;
/**
* struct qsee_rsp_uefi_set_variable - Response for the SetVariable command.
* @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE.
* @length: The length of this response, i.e. the size of this struct in
* bytes.
* @status: Status of this command.
* @_unknown1: Unknown response field.
* @_unknown2: Unknown response field.
*/
struct qsee_rsp_uefi_set_variable {
u32 command_id;
u32 length;
u32 status;
u32 _unknown1;
u32 _unknown2;
} __packed;
/**
* struct qsee_req_uefi_get_next_variable - Request for the
* GetNextVariableName command.
* @command_id: The ID of the command. Must be
* %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
* @length: Length of the request in bytes, including this struct and any
* parameters (name, GUID) stored after it as well as any padding
* thereof for alignment.
* @guid_offset: Offset from the start of this struct to where the GUID
* parameter is stored, in bytes.
* @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
* @name_offset: Offset from the start of this struct to where the variable
* name is stored (as utf-16 string), in bytes.
* @name_size: Size of the name parameter in bytes, including null-terminator.
*/
struct qsee_req_uefi_get_next_variable {
u32 command_id;
u32 length;
u32 guid_offset;
u32 guid_size;
u32 name_offset;
u32 name_size;
} __packed;
/**
* struct qsee_rsp_uefi_get_next_variable - Response for the
* GetNextVariableName command.
* @command_id: The ID of the command. Should be
* %QSEE_CMD_UEFI_GET_NEXT_VARIABLE.
* @length: Length of the response in bytes, including this struct and any
* parameters (name, GUID) stored after it as well as any padding
* thereof for alignment.
* @status: Status of this command.
* @guid_offset: Offset from the start of this struct to where the GUID
* parameter is stored, in bytes.
* @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t).
* @name_offset: Offset from the start of this struct to where the variable
* name is stored (as utf-16 string), in bytes.
* @name_size: Size of the name parameter in bytes, including null-terminator.
*/
struct qsee_rsp_uefi_get_next_variable {
u32 command_id;
u32 length;
u32 status;
u32 guid_offset;
u32 guid_size;
u32 name_offset;
u32 name_size;
} __packed;
/**
* struct qsee_req_uefi_query_variable_info - Response for the
* GetNextVariableName command.
* @command_id: The ID of the command. Must be
* %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
* @length: The length of this request, i.e. the size of this struct in
* bytes.
* @attributes: The storage attributes to query the info for.
*/
struct qsee_req_uefi_query_variable_info {
u32 command_id;
u32 length;
u32 attributes;
} __packed;
/**
* struct qsee_rsp_uefi_query_variable_info - Response for the
* GetNextVariableName command.
* @command_id: The ID of the command. Must be
* %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO.
* @length: The length of this response, i.e. the size of this
* struct in bytes.
* @status: Status of this command.
* @_pad: Padding.
* @storage_space: Full storage space size, in bytes.
* @remaining_space: Free storage space available, in bytes.
* @max_variable_size: Maximum variable data size, in bytes.
*/
struct qsee_rsp_uefi_query_variable_info {
u32 command_id;
u32 length;
u32 status;
u32 _pad;
u64 storage_space;
u64 remaining_space;
u64 max_variable_size;
} __packed;
/* -- Alignment helpers ----------------------------------------------------- */
/*
* Helper macro to ensure proper alignment of types (fields and arrays) when
* stored in some (contiguous) buffer.
*
* Note: The driver from which this one has been reverse-engineered expects an
* alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t,
* however, has an alignment of 4 byte (32 bits). So far, this seems to work
* fine here. See also the comment on the typedef of efi_guid_t.
*/
#define qcuefi_buf_align_fields(fields...) \
({ \
size_t __len = 0; \
fields \
__len; \
})
#define __field_impl(size, align, offset) \
({ \
size_t *__offset = (offset); \
size_t __aligned; \
\
__aligned = ALIGN(__len, align); \
__len = __aligned + (size); \
\
if (__offset) \
*__offset = __aligned; \
});
#define __array_offs(type, count, offset) \
__field_impl(sizeof(type) * (count), __alignof__(type), offset)
#define __array(type, count) __array_offs(type, count, NULL)
#define __field_offs(type, offset) __array_offs(type, 1, offset)
#define __field(type) __array_offs(type, 1, NULL)
/* -- UEFI app interface. --------------------------------------------------- */
struct qcuefi_client {
struct qseecom_client *client;
struct efivars efivars;
};
static struct device *qcuefi_dev(struct qcuefi_client *qcuefi)
{
return &qcuefi->client->aux_dev.dev;
}
static efi_status_t qsee_uefi_status_to_efi(u32 status)
{
u64 category = status & 0xf0000000;
u64 code = status & 0x0fffffff;
return category << (BITS_PER_LONG - 32) | code;
}
static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
const efi_guid_t *guid, u32 *attributes,
unsigned long *data_size, void *data)
{
struct qsee_req_uefi_get_variable *req_data;
struct qsee_rsp_uefi_get_variable *rsp_data;
unsigned long buffer_size = *data_size;
efi_status_t efi_status = EFI_SUCCESS;
unsigned long name_length;
size_t guid_offs;
size_t name_offs;
size_t req_size;
size_t rsp_size;
ssize_t status;
if (!name || !guid)
return EFI_INVALID_PARAMETER;
name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
if (name_length > QSEE_MAX_NAME_LEN)
return EFI_INVALID_PARAMETER;
if (buffer_size && !data)
return EFI_INVALID_PARAMETER;
req_size = qcuefi_buf_align_fields(
__field(*req_data)
__array_offs(*name, name_length, &name_offs)
__field_offs(*guid, &guid_offs)
);
rsp_size = qcuefi_buf_align_fields(
__field(*rsp_data)
__array(u8, buffer_size)
);
req_data = kzalloc(req_size, GFP_KERNEL);
if (!req_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out;
}
rsp_data = kzalloc(rsp_size, GFP_KERNEL);
if (!rsp_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out_free_req;
}
req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE;
req_data->data_size = buffer_size;
req_data->name_offset = name_offs;
req_data->name_size = name_length * sizeof(*name);
req_data->guid_offset = guid_offs;
req_data->guid_size = sizeof(*guid);
req_data->length = req_size;
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
if (status < 0)
return EFI_INVALID_PARAMETER;
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
if (status) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->length < sizeof(*rsp_data)) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->status) {
dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
__func__, rsp_data->status);
efi_status = qsee_uefi_status_to_efi(rsp_data->status);
/* Update size and attributes in case buffer is too small. */
if (efi_status == EFI_BUFFER_TOO_SMALL) {
*data_size = rsp_data->data_size;
if (attributes)
*attributes = rsp_data->attributes;
}
goto out_free;
}
if (rsp_data->length > rsp_size) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
/*
* Note: We need to set attributes and data size even if the buffer is
* too small and we won't copy any data. This is described in spec, so
* that callers can either allocate a buffer properly (with two calls
* to this function) or just read back attributes withouth having to
* deal with that.
*
* Specifically:
* - If we have a buffer size of zero and no buffer, just return the
* attributes, required size, and indicate success.
* - If the buffer size is nonzero but too small, indicate that as an
* error.
* - Otherwise, we are good to copy the data.
*
* Note that we have already ensured above that the buffer pointer is
* non-NULL if its size is nonzero.
*/
*data_size = rsp_data->data_size;
if (attributes)
*attributes = rsp_data->attributes;
if (buffer_size == 0 && !data) {
efi_status = EFI_SUCCESS;
goto out_free;
}
if (buffer_size < rsp_data->data_size) {
efi_status = EFI_BUFFER_TOO_SMALL;
goto out_free;
}
memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size);
out_free:
kfree(rsp_data);
out_free_req:
kfree(req_data);
out:
return efi_status;
}
static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name,
const efi_guid_t *guid, u32 attributes,
unsigned long data_size, const void *data)
{
struct qsee_req_uefi_set_variable *req_data;
struct qsee_rsp_uefi_set_variable *rsp_data;
efi_status_t efi_status = EFI_SUCCESS;
unsigned long name_length;
size_t name_offs;
size_t guid_offs;
size_t data_offs;
size_t req_size;
ssize_t status;
if (!name || !guid)
return EFI_INVALID_PARAMETER;
name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1;
if (name_length > QSEE_MAX_NAME_LEN)
return EFI_INVALID_PARAMETER;
/*
* Make sure we have some data if data_size is nonzero. Note that using
* a size of zero is a valid use-case described in spec and deletes the
* variable.
*/
if (data_size && !data)
return EFI_INVALID_PARAMETER;
req_size = qcuefi_buf_align_fields(
__field(*req_data)
__array_offs(*name, name_length, &name_offs)
__field_offs(*guid, &guid_offs)
__array_offs(u8, data_size, &data_offs)
);
req_data = kzalloc(req_size, GFP_KERNEL);
if (!req_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out;
}
rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
if (!rsp_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out_free_req;
}
req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE;
req_data->attributes = attributes;
req_data->name_offset = name_offs;
req_data->name_size = name_length * sizeof(*name);
req_data->guid_offset = guid_offs;
req_data->guid_size = sizeof(*guid);
req_data->data_offset = data_offs;
req_data->data_size = data_size;
req_data->length = req_size;
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length);
if (status < 0)
return EFI_INVALID_PARAMETER;
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
if (data_size)
memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size);
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data,
sizeof(*rsp_data));
if (status) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->length != sizeof(*rsp_data)) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->status) {
dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
__func__, rsp_data->status);
efi_status = qsee_uefi_status_to_efi(rsp_data->status);
}
out_free:
kfree(rsp_data);
out_free_req:
kfree(req_data);
out:
return efi_status;
}
static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi,
unsigned long *name_size, efi_char16_t *name,
efi_guid_t *guid)
{
struct qsee_req_uefi_get_next_variable *req_data;
struct qsee_rsp_uefi_get_next_variable *rsp_data;
efi_status_t efi_status = EFI_SUCCESS;
size_t guid_offs;
size_t name_offs;
size_t req_size;
size_t rsp_size;
ssize_t status;
if (!name_size || !name || !guid)
return EFI_INVALID_PARAMETER;
if (*name_size == 0)
return EFI_INVALID_PARAMETER;
req_size = qcuefi_buf_align_fields(
__field(*req_data)
__field_offs(*guid, &guid_offs)
__array_offs(*name, *name_size / sizeof(*name), &name_offs)
);
rsp_size = qcuefi_buf_align_fields(
__field(*rsp_data)
__field(*guid)
__array(*name, *name_size / sizeof(*name))
);
req_data = kzalloc(req_size, GFP_KERNEL);
if (!req_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out;
}
rsp_data = kzalloc(rsp_size, GFP_KERNEL);
if (!rsp_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out_free_req;
}
req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE;
req_data->guid_offset = guid_offs;
req_data->guid_size = sizeof(*guid);
req_data->name_offset = name_offs;
req_data->name_size = *name_size;
req_data->length = req_size;
memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size);
status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name,
*name_size / sizeof(*name));
if (status < 0)
return EFI_INVALID_PARAMETER;
status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size);
if (status) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->length < sizeof(*rsp_data)) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->status) {
dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
__func__, rsp_data->status);
efi_status = qsee_uefi_status_to_efi(rsp_data->status);
/*
* If the buffer to hold the name is too small, update the
* name_size with the required size, so that callers can
* reallocate it accordingly.
*/
if (efi_status == EFI_BUFFER_TOO_SMALL)
*name_size = rsp_data->name_size;
goto out_free;
}
if (rsp_data->length > rsp_size) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->name_size > *name_size) {
*name_size = rsp_data->name_size;
efi_status = EFI_BUFFER_TOO_SMALL;
goto out_free;
}
if (rsp_data->guid_size != sizeof(*guid)) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size);
status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset,
rsp_data->name_size / sizeof(*name));
*name_size = rsp_data->name_size;
if (status < 0) {
/*
* Return EFI_DEVICE_ERROR here because the buffer size should
* have already been validated above, causing this function to
* bail with EFI_BUFFER_TOO_SMALL.
*/
return EFI_DEVICE_ERROR;
}
out_free:
kfree(rsp_data);
out_free_req:
kfree(req_data);
out:
return efi_status;
}
static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr,
u64 *storage_space, u64 *remaining_space,
u64 *max_variable_size)
{
struct qsee_req_uefi_query_variable_info *req_data;
struct qsee_rsp_uefi_query_variable_info *rsp_data;
efi_status_t efi_status = EFI_SUCCESS;
int status;
req_data = kzalloc(sizeof(*req_data), GFP_KERNEL);
if (!req_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out;
}
rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL);
if (!rsp_data) {
efi_status = EFI_OUT_OF_RESOURCES;
goto out_free_req;
}
req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO;
req_data->attributes = attr;
req_data->length = sizeof(*req_data);
status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data,
sizeof(*rsp_data));
if (status) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->length != sizeof(*rsp_data)) {
efi_status = EFI_DEVICE_ERROR;
goto out_free;
}
if (rsp_data->status) {
dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n",
__func__, rsp_data->status);
efi_status = qsee_uefi_status_to_efi(rsp_data->status);
goto out_free;
}
if (storage_space)
*storage_space = rsp_data->storage_space;
if (remaining_space)
*remaining_space = rsp_data->remaining_space;
if (max_variable_size)
*max_variable_size = rsp_data->max_variable_size;
out_free:
kfree(rsp_data);
out_free_req:
kfree(req_data);
out:
return efi_status;
}
/* -- Global efivar interface. ---------------------------------------------- */
static struct qcuefi_client *__qcuefi;
static DEFINE_MUTEX(__qcuefi_lock);
static int qcuefi_set_reference(struct qcuefi_client *qcuefi)
{
mutex_lock(&__qcuefi_lock);
if (qcuefi && __qcuefi) {
mutex_unlock(&__qcuefi_lock);
return -EEXIST;
}
__qcuefi = qcuefi;
mutex_unlock(&__qcuefi_lock);
return 0;
}
static struct qcuefi_client *qcuefi_acquire(void)
{
mutex_lock(&__qcuefi_lock);
return __qcuefi;
}
static void qcuefi_release(void)
{
mutex_unlock(&__qcuefi_lock);
}
static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
unsigned long *data_size, void *data)
{
struct qcuefi_client *qcuefi;
efi_status_t status;
qcuefi = qcuefi_acquire();
if (!qcuefi)
return EFI_NOT_READY;
status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data);
qcuefi_release();
return status;
}
static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor,
u32 attr, unsigned long data_size, void *data)
{
struct qcuefi_client *qcuefi;
efi_status_t status;
qcuefi = qcuefi_acquire();
if (!qcuefi)
return EFI_NOT_READY;
status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data);
qcuefi_release();
return status;
}
static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name,
efi_guid_t *vendor)
{
struct qcuefi_client *qcuefi;
efi_status_t status;
qcuefi = qcuefi_acquire();
if (!qcuefi)
return EFI_NOT_READY;
status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor);
qcuefi_release();
return status;
}
static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
u64 *max_variable_size)
{
struct qcuefi_client *qcuefi;
efi_status_t status;
qcuefi = qcuefi_acquire();
if (!qcuefi)
return EFI_NOT_READY;
status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space,
max_variable_size);
qcuefi_release();
return status;
}
static const struct efivar_operations qcom_efivar_ops = {
.get_variable = qcuefi_get_variable,
.set_variable = qcuefi_set_variable,
.get_next_variable = qcuefi_get_next_variable,
.query_variable_info = qcuefi_query_variable_info,
};
/* -- Driver setup. --------------------------------------------------------- */
static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev,
const struct auxiliary_device_id *aux_dev_id)
{
struct qcuefi_client *qcuefi;
int status;
qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL);
if (!qcuefi)
return -ENOMEM;
qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev);
auxiliary_set_drvdata(aux_dev, qcuefi);
status = qcuefi_set_reference(qcuefi);
if (status)
return status;
status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops);
if (status)
qcuefi_set_reference(NULL);
return status;
}
static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev)
{
struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev);
efivars_unregister(&qcuefi->efivars);
qcuefi_set_reference(NULL);
}
static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = {
{ .name = "qcom_qseecom.uefisecapp" },
{}
};
MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table);
static struct auxiliary_driver qcom_uefisecapp_driver = {
.probe = qcom_uefisecapp_probe,
.remove = qcom_uefisecapp_remove,
.id_table = qcom_uefisecapp_id_table,
.driver = {
.name = "qcom_qseecom_uefisecapp",
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_auxiliary_driver(qcom_uefisecapp_driver);
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App");
MODULE_LICENSE("GPL");

View File

@ -2,24 +2,25 @@
/* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved.
* Copyright (C) 2015 Linaro Ltd.
*/
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/cpumask.h>
#include <linux/export.h>
#include <linux/dma-mapping.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/export.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/init.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
#include <linux/reset-controller.h>
#include <linux/arm-smccc.h>
#include <linux/types.h>
#include "qcom_scm.h"
@ -55,6 +56,53 @@ struct qcom_scm_mem_map_info {
__le64 mem_size;
};
/**
* struct qcom_scm_qseecom_resp - QSEECOM SCM call response.
* @result: Result or status of the SCM call. See &enum qcom_scm_qseecom_result.
* @resp_type: Type of the response. See &enum qcom_scm_qseecom_resp_type.
* @data: Response data. The type of this data is given in @resp_type.
*/
struct qcom_scm_qseecom_resp {
u64 result;
u64 resp_type;
u64 data;
};
enum qcom_scm_qseecom_result {
QSEECOM_RESULT_SUCCESS = 0,
QSEECOM_RESULT_INCOMPLETE = 1,
QSEECOM_RESULT_BLOCKED_ON_LISTENER = 2,
QSEECOM_RESULT_FAILURE = 0xFFFFFFFF,
};
enum qcom_scm_qseecom_resp_type {
QSEECOM_SCM_RES_APP_ID = 0xEE01,
QSEECOM_SCM_RES_QSEOS_LISTENER_ID = 0xEE02,
};
enum qcom_scm_qseecom_tz_owner {
QSEECOM_TZ_OWNER_SIP = 2,
QSEECOM_TZ_OWNER_TZ_APPS = 48,
QSEECOM_TZ_OWNER_QSEE_OS = 50
};
enum qcom_scm_qseecom_tz_svc {
QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER = 0,
QSEECOM_TZ_SVC_APP_MGR = 1,
QSEECOM_TZ_SVC_INFO = 6,
};
enum qcom_scm_qseecom_tz_cmd_app {
QSEECOM_TZ_CMD_APP_SEND = 1,
QSEECOM_TZ_CMD_APP_LOOKUP = 3,
};
enum qcom_scm_qseecom_tz_cmd_info {
QSEECOM_TZ_CMD_INFO_VERSION = 3,
};
#define QSEECOM_MAX_APP_NAME_SIZE 64
/* Each bit configures cold/warm boot address for one of the 4 CPUs */
static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = {
0, BIT(0), BIT(3), BIT(5)
@ -167,6 +215,12 @@ static enum qcom_scm_convention __get_convention(void)
if (likely(qcom_scm_convention != SMC_CONVENTION_UNKNOWN))
return qcom_scm_convention;
/*
* Per the "SMC calling convention specification", the 64-bit calling
* convention can only be used when the client is 64-bit, otherwise
* system will encounter the undefined behaviour.
*/
#if IS_ENABLED(CONFIG_ARM64)
/*
* Device isn't required as there is only one argument - no device
* needed to dma_map_single to secure world
@ -187,6 +241,7 @@ static enum qcom_scm_convention __get_convention(void)
forced = true;
goto found;
}
#endif
probed_convention = SMC_CONVENTION_ARM_32;
ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true);
@ -403,6 +458,29 @@ int qcom_scm_set_remote_state(u32 state, u32 id)
}
EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state);
static int qcom_scm_disable_sdi(void)
{
int ret;
struct qcom_scm_desc desc = {
.svc = QCOM_SCM_SVC_BOOT,
.cmd = QCOM_SCM_BOOT_SDI_CONFIG,
.args[0] = 1, /* Disable watchdog debug */
.args[1] = 0, /* Disable SDI */
.arginfo = QCOM_SCM_ARGS(2),
.owner = ARM_SMCCC_OWNER_SIP,
};
struct qcom_scm_res res;
ret = qcom_scm_clk_enable();
if (ret)
return ret;
ret = qcom_scm_call(__scm->dev, &desc, &res);
qcom_scm_clk_disable();
return ret ? : res.result[0];
}
static int __qcom_scm_set_dload_mode(struct device *dev, bool enable)
{
struct qcom_scm_desc desc = {
@ -1321,6 +1399,340 @@ static int qcom_scm_find_dload_address(struct device *dev, u64 *addr)
return 0;
}
#ifdef CONFIG_QCOM_QSEECOM
/* Lock for QSEECOM SCM call executions */
static DEFINE_MUTEX(qcom_scm_qseecom_call_lock);
static int __qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
struct qcom_scm_qseecom_resp *res)
{
struct qcom_scm_res scm_res = {};
int status;
/*
* QSEECOM SCM calls should not be executed concurrently. Therefore, we
* require the respective call lock to be held.
*/
lockdep_assert_held(&qcom_scm_qseecom_call_lock);
status = qcom_scm_call(__scm->dev, desc, &scm_res);
res->result = scm_res.result[0];
res->resp_type = scm_res.result[1];
res->data = scm_res.result[2];
if (status)
return status;
return 0;
}
/**
* qcom_scm_qseecom_call() - Perform a QSEECOM SCM call.
* @desc: SCM call descriptor.
* @res: SCM call response (output).
*
* Performs the QSEECOM SCM call described by @desc, returning the response in
* @rsp.
*
* Return: Zero on success, nonzero on failure.
*/
static int qcom_scm_qseecom_call(const struct qcom_scm_desc *desc,
struct qcom_scm_qseecom_resp *res)
{
int status;
/*
* Note: Multiple QSEECOM SCM calls should not be executed same time,
* so lock things here. This needs to be extended to callback/listener
* handling when support for that is implemented.
*/
mutex_lock(&qcom_scm_qseecom_call_lock);
status = __qcom_scm_qseecom_call(desc, res);
mutex_unlock(&qcom_scm_qseecom_call_lock);
dev_dbg(__scm->dev, "%s: owner=%x, svc=%x, cmd=%x, result=%lld, type=%llx, data=%llx\n",
__func__, desc->owner, desc->svc, desc->cmd, res->result,
res->resp_type, res->data);
if (status) {
dev_err(__scm->dev, "qseecom: scm call failed with error %d\n", status);
return status;
}
/*
* TODO: Handle incomplete and blocked calls:
*
* Incomplete and blocked calls are not supported yet. Some devices
* and/or commands require those, some don't. Let's warn about them
* prominently in case someone attempts to try these commands with a
* device/command combination that isn't supported yet.
*/
WARN_ON(res->result == QSEECOM_RESULT_INCOMPLETE);
WARN_ON(res->result == QSEECOM_RESULT_BLOCKED_ON_LISTENER);
return 0;
}
/**
* qcom_scm_qseecom_get_version() - Query the QSEECOM version.
* @version: Pointer where the QSEECOM version will be stored.
*
* Performs the QSEECOM SCM querying the QSEECOM version currently running in
* the TrustZone.
*
* Return: Zero on success, nonzero on failure.
*/
static int qcom_scm_qseecom_get_version(u32 *version)
{
struct qcom_scm_desc desc = {};
struct qcom_scm_qseecom_resp res = {};
u32 feature = 10;
int ret;
desc.owner = QSEECOM_TZ_OWNER_SIP;
desc.svc = QSEECOM_TZ_SVC_INFO;
desc.cmd = QSEECOM_TZ_CMD_INFO_VERSION;
desc.arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL);
desc.args[0] = feature;
ret = qcom_scm_qseecom_call(&desc, &res);
if (ret)
return ret;
*version = res.result;
return 0;
}
/**
* qcom_scm_qseecom_app_get_id() - Query the app ID for a given QSEE app name.
* @app_name: The name of the app.
* @app_id: The returned app ID.
*
* Query and return the application ID of the SEE app identified by the given
* name. This returned ID is the unique identifier of the app required for
* subsequent communication.
*
* Return: Zero on success, nonzero on failure, -ENOENT if the app has not been
* loaded or could not be found.
*/
int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id)
{
unsigned long name_buf_size = QSEECOM_MAX_APP_NAME_SIZE;
unsigned long app_name_len = strlen(app_name);
struct qcom_scm_desc desc = {};
struct qcom_scm_qseecom_resp res = {};
dma_addr_t name_buf_phys;
char *name_buf;
int status;
if (app_name_len >= name_buf_size)
return -EINVAL;
name_buf = kzalloc(name_buf_size, GFP_KERNEL);
if (!name_buf)
return -ENOMEM;
memcpy(name_buf, app_name, app_name_len);
name_buf_phys = dma_map_single(__scm->dev, name_buf, name_buf_size, DMA_TO_DEVICE);
status = dma_mapping_error(__scm->dev, name_buf_phys);
if (status) {
kfree(name_buf);
dev_err(__scm->dev, "qseecom: failed to map dma address\n");
return status;
}
desc.owner = QSEECOM_TZ_OWNER_QSEE_OS;
desc.svc = QSEECOM_TZ_SVC_APP_MGR;
desc.cmd = QSEECOM_TZ_CMD_APP_LOOKUP;
desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL);
desc.args[0] = name_buf_phys;
desc.args[1] = app_name_len;
status = qcom_scm_qseecom_call(&desc, &res);
dma_unmap_single(__scm->dev, name_buf_phys, name_buf_size, DMA_TO_DEVICE);
kfree(name_buf);
if (status)
return status;
if (res.result == QSEECOM_RESULT_FAILURE)
return -ENOENT;
if (res.result != QSEECOM_RESULT_SUCCESS)
return -EINVAL;
if (res.resp_type != QSEECOM_SCM_RES_APP_ID)
return -EINVAL;
*app_id = res.data;
return 0;
}
EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id);
/**
* qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app.
* @app_id: The ID of the target app.
* @req: Request buffer sent to the app (must be DMA-mappable).
* @req_size: Size of the request buffer.
* @rsp: Response buffer, written to by the app (must be DMA-mappable).
* @rsp_size: Size of the response buffer.
*
* Sends a request to the QSEE app associated with the given ID and read back
* its response. The caller must provide two DMA memory regions, one for the
* request and one for the response, and fill out the @req region with the
* respective (app-specific) request data. The QSEE app reads this and returns
* its response in the @rsp region.
*
* Return: Zero on success, nonzero on failure.
*/
int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp,
size_t rsp_size)
{
struct qcom_scm_qseecom_resp res = {};
struct qcom_scm_desc desc = {};
dma_addr_t req_phys;
dma_addr_t rsp_phys;
int status;
/* Map request buffer */
req_phys = dma_map_single(__scm->dev, req, req_size, DMA_TO_DEVICE);
status = dma_mapping_error(__scm->dev, req_phys);
if (status) {
dev_err(__scm->dev, "qseecom: failed to map request buffer\n");
return status;
}
/* Map response buffer */
rsp_phys = dma_map_single(__scm->dev, rsp, rsp_size, DMA_FROM_DEVICE);
status = dma_mapping_error(__scm->dev, rsp_phys);
if (status) {
dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
dev_err(__scm->dev, "qseecom: failed to map response buffer\n");
return status;
}
/* Set up SCM call data */
desc.owner = QSEECOM_TZ_OWNER_TZ_APPS;
desc.svc = QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER;
desc.cmd = QSEECOM_TZ_CMD_APP_SEND;
desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL,
QCOM_SCM_RW, QCOM_SCM_VAL,
QCOM_SCM_RW, QCOM_SCM_VAL);
desc.args[0] = app_id;
desc.args[1] = req_phys;
desc.args[2] = req_size;
desc.args[3] = rsp_phys;
desc.args[4] = rsp_size;
/* Perform call */
status = qcom_scm_qseecom_call(&desc, &res);
/* Unmap buffers */
dma_unmap_single(__scm->dev, rsp_phys, rsp_size, DMA_FROM_DEVICE);
dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE);
if (status)
return status;
if (res.result != QSEECOM_RESULT_SUCCESS)
return -EIO;
return 0;
}
EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
/*
* We do not yet support re-entrant calls via the qseecom interface. To prevent
+ any potential issues with this, only allow validated machines for now.
*/
static const struct of_device_id qcom_scm_qseecom_allowlist[] = {
{ .compatible = "lenovo,thinkpad-x13s", },
{ }
};
static bool qcom_scm_qseecom_machine_is_allowed(void)
{
struct device_node *np;
bool match;
np = of_find_node_by_path("/");
if (!np)
return false;
match = of_match_node(qcom_scm_qseecom_allowlist, np);
of_node_put(np);
return match;
}
static void qcom_scm_qseecom_free(void *data)
{
struct platform_device *qseecom_dev = data;
platform_device_del(qseecom_dev);
platform_device_put(qseecom_dev);
}
static int qcom_scm_qseecom_init(struct qcom_scm *scm)
{
struct platform_device *qseecom_dev;
u32 version;
int ret;
/*
* Note: We do two steps of validation here: First, we try to query the
* QSEECOM version as a check to see if the interface exists on this
* device. Second, we check against known good devices due to current
* driver limitations (see comment in qcom_scm_qseecom_allowlist).
*
* Note that we deliberately do the machine check after the version
* check so that we can log potentially supported devices. This should
* be safe as downstream sources indicate that the version query is
* neither blocking nor reentrant.
*/
ret = qcom_scm_qseecom_get_version(&version);
if (ret)
return 0;
dev_info(scm->dev, "qseecom: found qseecom with version 0x%x\n", version);
if (!qcom_scm_qseecom_machine_is_allowed()) {
dev_info(scm->dev, "qseecom: untested machine, skipping\n");
return 0;
}
/*
* Set up QSEECOM interface device. All application clients will be
* set up and managed by the corresponding driver for it.
*/
qseecom_dev = platform_device_alloc("qcom_qseecom", -1);
if (!qseecom_dev)
return -ENOMEM;
qseecom_dev->dev.parent = scm->dev;
ret = platform_device_add(qseecom_dev);
if (ret) {
platform_device_put(qseecom_dev);
return ret;
}
return devm_add_action_or_reset(scm->dev, qcom_scm_qseecom_free, qseecom_dev);
}
#else /* CONFIG_QCOM_QSEECOM */
static int qcom_scm_qseecom_init(struct qcom_scm *scm)
{
return 0;
}
#endif /* CONFIG_QCOM_QSEECOM */
/**
* qcom_scm_is_available() - Checks if SCM is available
*/
@ -1468,6 +1880,26 @@ static int qcom_scm_probe(struct platform_device *pdev)
if (download_mode)
qcom_scm_set_download_mode(true);
/*
* Disable SDI if indicated by DT that it is enabled by default.
*/
if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled"))
qcom_scm_disable_sdi();
/*
* Initialize the QSEECOM interface.
*
* Note: QSEECOM is fairly self-contained and this only adds the
* interface device (the driver of which does most of the heavy
* lifting). So any errors returned here should be either -ENOMEM or
* -EINVAL (with the latter only in case there's a bug in our code).
* This means that there is no need to bring down the whole SCM driver.
* Just log the error instead and let SCM live.
*/
ret = qcom_scm_qseecom_init(scm);
WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
return 0;
}

View File

@ -80,6 +80,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
#define QCOM_SCM_SVC_BOOT 0x01
#define QCOM_SCM_BOOT_SET_ADDR 0x01
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
#define QCOM_SCM_BOOT_SDI_CONFIG 0x09
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a

View File

@ -133,7 +133,7 @@ int cmd_db_ready(void)
return 0;
}
EXPORT_SYMBOL(cmd_db_ready);
EXPORT_SYMBOL_GPL(cmd_db_ready);
static int cmd_db_get_header(const char *id, const struct entry_header **eh,
const struct rsc_hdr **rh)
@ -193,7 +193,7 @@ u32 cmd_db_read_addr(const char *id)
return ret < 0 ? 0 : le32_to_cpu(ent->addr);
}
EXPORT_SYMBOL(cmd_db_read_addr);
EXPORT_SYMBOL_GPL(cmd_db_read_addr);
/**
* cmd_db_read_aux_data() - Query command db for aux data.
@ -218,7 +218,7 @@ const void *cmd_db_read_aux_data(const char *id, size_t *len)
return rsc_offset(rsc_hdr, ent);
}
EXPORT_SYMBOL(cmd_db_read_aux_data);
EXPORT_SYMBOL_GPL(cmd_db_read_aux_data);
/**
* cmd_db_read_slave_id - Get the slave ID for a given resource address
@ -240,7 +240,7 @@ enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
addr = le32_to_cpu(ent->addr);
return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
}
EXPORT_SYMBOL(cmd_db_read_slave_id);
EXPORT_SYMBOL_GPL(cmd_db_read_slave_id);
#ifdef CONFIG_DEBUG_FS
static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)

View File

@ -793,13 +793,11 @@ static int bwmon_probe(struct platform_device *pdev)
return 0;
}
static int bwmon_remove(struct platform_device *pdev)
static void bwmon_remove(struct platform_device *pdev)
{
struct icc_bwmon *bwmon = platform_get_drvdata(pdev);
bwmon_disable(bwmon);
return 0;
}
static const struct icc_bwmon_data msm8998_bwmon_data = {
@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, bwmon_of_match);
static struct platform_driver bwmon_driver = {
.probe = bwmon_probe,
.remove = bwmon_remove,
.remove_new = bwmon_remove,
.driver = {
.name = "qcom-bwmon",
.of_match_table = bwmon_of_match,

View File

@ -32,7 +32,7 @@ void kryo_l2_set_indirect_reg(u64 reg, u64 val)
isb();
raw_spin_unlock_irqrestore(&l2_access_lock, flags);
}
EXPORT_SYMBOL(kryo_l2_set_indirect_reg);
EXPORT_SYMBOL_GPL(kryo_l2_set_indirect_reg);
/**
* kryo_l2_get_indirect_reg() - read an L2 register value
@ -54,4 +54,4 @@ u64 kryo_l2_get_indirect_reg(u64 reg)
return val;
}
EXPORT_SYMBOL(kryo_l2_get_indirect_reg);
EXPORT_SYMBOL_GPL(kryo_l2_get_indirect_reg);

View File

@ -12,6 +12,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/nvmem-consumer.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
@ -126,6 +127,11 @@ struct qcom_llcc_config {
bool no_edac;
};
struct qcom_sct_config {
const struct qcom_llcc_config *llcc_config;
int num_config;
};
enum llcc_reg_offset {
LLCC_COMMON_HW_INFO,
LLCC_COMMON_STATUS0,
@ -185,7 +191,7 @@ static const struct llcc_slice_config sc8280xp_data[] = {
{ LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
{ LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
{ LLCC_AUDHW, 22, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
{ LLCC_DRE, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
{ LLCC_ECC, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
{ LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 },
{ LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0, 0 },
{ LLCC_WRCACHE, 31, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 },
@ -356,6 +362,36 @@ static const struct llcc_slice_config sm8550_data[] = {
{LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
};
static const struct llcc_slice_config qdu1000_data_2ch[] = {
{ LLCC_MDMHPGRW, 7, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MODHW, 9, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MDMPNG, 21, 256, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_ECC, 26, 512, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{ LLCC_MODPE, 29, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_APTCM, 30, 256, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
{ LLCC_WRCACHE, 31, 128, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
};
static const struct llcc_slice_config qdu1000_data_4ch[] = {
{ LLCC_MDMHPGRW, 7, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MODHW, 9, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MDMPNG, 21, 512, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_ECC, 26, 1024, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{ LLCC_MODPE, 29, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_APTCM, 30, 512, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
{ LLCC_WRCACHE, 31, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
};
static const struct llcc_slice_config qdu1000_data_8ch[] = {
{ LLCC_MDMHPGRW, 7, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_MDMPNG, 21, 1024, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_ECC, 26, 2048, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 },
{ LLCC_MODPE, 29, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 },
{ LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 },
{ LLCC_WRCACHE, 31, 512, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 },
};
static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = {
.trp_ecc_error_status0 = 0x20344,
.trp_ecc_error_status1 = 0x20348,
@ -422,101 +458,221 @@ static const u32 llcc_v2_1_reg_offset[] = {
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
static const struct qcom_llcc_config sc7180_cfg = {
.sct_data = sc7180_data,
.size = ARRAY_SIZE(sc7180_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config qdu1000_cfg[] = {
{
.sct_data = qdu1000_data_8ch,
.size = ARRAY_SIZE(qdu1000_data_8ch),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_4ch,
.size = ARRAY_SIZE(qdu1000_data_4ch),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_4ch,
.size = ARRAY_SIZE(qdu1000_data_4ch),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
{
.sct_data = qdu1000_data_2ch,
.size = ARRAY_SIZE(qdu1000_data_2ch),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sc7280_cfg = {
.sct_data = sc7280_data,
.size = ARRAY_SIZE(sc7280_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sc7180_cfg[] = {
{
.sct_data = sc7180_data,
.size = ARRAY_SIZE(sc7180_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sc8180x_cfg = {
.sct_data = sc8180x_data,
.size = ARRAY_SIZE(sc8180x_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sc7280_cfg[] = {
{
.sct_data = sc7280_data,
.size = ARRAY_SIZE(sc7280_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sc8280xp_cfg = {
.sct_data = sc8280xp_data,
.size = ARRAY_SIZE(sc8280xp_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sc8180x_cfg[] = {
{
.sct_data = sc8180x_data,
.size = ARRAY_SIZE(sc8180x_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sdm845_cfg = {
.sct_data = sdm845_data,
.size = ARRAY_SIZE(sdm845_data),
.need_llcc_cfg = false,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
.no_edac = true,
static const struct qcom_llcc_config sc8280xp_cfg[] = {
{
.sct_data = sc8280xp_data,
.size = ARRAY_SIZE(sc8280xp_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm6350_cfg = {
.sct_data = sm6350_data,
.size = ARRAY_SIZE(sm6350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sdm845_cfg[] = {
{
.sct_data = sdm845_data,
.size = ARRAY_SIZE(sdm845_data),
.need_llcc_cfg = false,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
.no_edac = true,
},
};
static const struct qcom_llcc_config sm7150_cfg = {
.sct_data = sm7150_data,
.size = ARRAY_SIZE(sm7150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sm6350_cfg[] = {
{
.sct_data = sm6350_data,
.size = ARRAY_SIZE(sm6350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8150_cfg = {
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sm7150_cfg[] = {
{
.sct_data = sm7150_data,
.size = ARRAY_SIZE(sm7150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8250_cfg = {
.sct_data = sm8250_data,
.size = ARRAY_SIZE(sm8250_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sm8150_cfg[] = {
{
.sct_data = sm8150_data,
.size = ARRAY_SIZE(sm8150_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8350_cfg = {
.sct_data = sm8350_data,
.size = ARRAY_SIZE(sm8350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
static const struct qcom_llcc_config sm8250_cfg[] = {
{
.sct_data = sm8250_data,
.size = ARRAY_SIZE(sm8250_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8450_cfg = {
.sct_data = sm8450_data,
.size = ARRAY_SIZE(sm8450_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
static const struct qcom_llcc_config sm8350_cfg[] = {
{
.sct_data = sm8350_data,
.size = ARRAY_SIZE(sm8350_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v1_reg_offset,
.edac_reg_offset = &llcc_v1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8550_cfg = {
.sct_data = sm8550_data,
.size = ARRAY_SIZE(sm8550_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
static const struct qcom_llcc_config sm8450_cfg[] = {
{
.sct_data = sm8450_data,
.size = ARRAY_SIZE(sm8450_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
};
static const struct qcom_llcc_config sm8550_cfg[] = {
{
.sct_data = sm8550_data,
.size = ARRAY_SIZE(sm8550_data),
.need_llcc_cfg = true,
.reg_offset = llcc_v2_1_reg_offset,
.edac_reg_offset = &llcc_v2_1_edac_reg_offset,
},
};
static const struct qcom_sct_config qdu1000_cfgs = {
.llcc_config = qdu1000_cfg,
.num_config = ARRAY_SIZE(qdu1000_cfg),
};
static const struct qcom_sct_config sc7180_cfgs = {
.llcc_config = sc7180_cfg,
.num_config = ARRAY_SIZE(sc7180_cfg),
};
static const struct qcom_sct_config sc7280_cfgs = {
.llcc_config = sc7280_cfg,
.num_config = ARRAY_SIZE(sc7280_cfg),
};
static const struct qcom_sct_config sc8180x_cfgs = {
.llcc_config = sc8180x_cfg,
.num_config = ARRAY_SIZE(sc8180x_cfg),
};
static const struct qcom_sct_config sc8280xp_cfgs = {
.llcc_config = sc8280xp_cfg,
.num_config = ARRAY_SIZE(sc8280xp_cfg),
};
static const struct qcom_sct_config sdm845_cfgs = {
.llcc_config = sdm845_cfg,
.num_config = ARRAY_SIZE(sdm845_cfg),
};
static const struct qcom_sct_config sm6350_cfgs = {
.llcc_config = sm6350_cfg,
.num_config = ARRAY_SIZE(sm6350_cfg),
};
static const struct qcom_sct_config sm7150_cfgs = {
.llcc_config = sm7150_cfg,
.num_config = ARRAY_SIZE(sm7150_cfg),
};
static const struct qcom_sct_config sm8150_cfgs = {
.llcc_config = sm8150_cfg,
.num_config = ARRAY_SIZE(sm8150_cfg),
};
static const struct qcom_sct_config sm8250_cfgs = {
.llcc_config = sm8250_cfg,
.num_config = ARRAY_SIZE(sm8250_cfg),
};
static const struct qcom_sct_config sm8350_cfgs = {
.llcc_config = sm8350_cfg,
.num_config = ARRAY_SIZE(sm8350_cfg),
};
static const struct qcom_sct_config sm8450_cfgs = {
.llcc_config = sm8450_cfg,
.num_config = ARRAY_SIZE(sm8450_cfg),
};
static const struct qcom_sct_config sm8550_cfgs = {
.llcc_config = sm8550_cfg,
.num_config = ARRAY_SIZE(sm8550_cfg),
};
static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER;
@ -906,11 +1062,28 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev,
return ret;
}
static int qcom_llcc_remove(struct platform_device *pdev)
static int qcom_llcc_get_cfg_index(struct platform_device *pdev, u8 *cfg_index, int num_config)
{
int ret;
ret = nvmem_cell_read_u8(&pdev->dev, "multi-chan-ddr", cfg_index);
if (ret == -ENOENT || ret == -EOPNOTSUPP) {
if (num_config > 1)
return -EINVAL;
*cfg_index = 0;
return 0;
}
if (!ret && *cfg_index >= num_config)
ret = -EINVAL;
return ret;
}
static void qcom_llcc_remove(struct platform_device *pdev)
{
/* Set the global pointer to a error code to avoid referencing it */
drv_data = ERR_PTR(-ENODEV);
return 0;
}
static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index,
@ -938,12 +1111,17 @@ static int qcom_llcc_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int ret, i;
struct platform_device *llcc_edac;
const struct qcom_sct_config *cfgs;
const struct qcom_llcc_config *cfg;
const struct llcc_slice_config *llcc_cfg;
u32 sz;
u8 cfg_index;
u32 version;
struct regmap *regmap;
if (!IS_ERR(drv_data))
return -EBUSY;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data) {
ret = -ENOMEM;
@ -957,7 +1135,15 @@ static int qcom_llcc_probe(struct platform_device *pdev)
goto err;
}
cfg = of_device_get_match_data(&pdev->dev);
cfgs = of_device_get_match_data(&pdev->dev);
if (!cfgs) {
ret = -EINVAL;
goto err;
}
ret = qcom_llcc_get_cfg_index(pdev, &cfg_index, cfgs->num_config);
if (ret)
goto err;
cfg = &cfgs->llcc_config[cfg_index];
ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks);
if (ret)
@ -1050,18 +1236,19 @@ err:
}
static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg },
{ .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg },
{ .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfg },
{ .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg },
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg },
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg },
{ .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfg },
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg },
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg },
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg },
{ .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg },
{ .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs},
{ .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfgs },
{ .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs },
{ .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs },
{ .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs },
{ .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs },
{ .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs },
{ .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs },
{ .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfgs },
{ .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfgs },
{ .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfgs },
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs },
{ .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs },
{ }
};
MODULE_DEVICE_TABLE(of, qcom_llcc_of_match);
@ -1072,7 +1259,7 @@ static struct platform_driver qcom_llcc_driver = {
.of_match_table = qcom_llcc_of_match,
},
.probe = qcom_llcc_probe,
.remove = qcom_llcc_remove,
.remove_new = qcom_llcc_remove,
};
module_platform_driver(qcom_llcc_driver);

View File

@ -211,7 +211,7 @@ struct ocmem *of_get_ocmem(struct device *dev)
}
return ocmem;
}
EXPORT_SYMBOL(of_get_ocmem);
EXPORT_SYMBOL_GPL(of_get_ocmem);
struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client,
unsigned long size)
@ -267,7 +267,7 @@ err_unlock:
return ERR_PTR(ret);
}
EXPORT_SYMBOL(ocmem_allocate);
EXPORT_SYMBOL_GPL(ocmem_allocate);
void ocmem_free(struct ocmem *ocmem, enum ocmem_client client,
struct ocmem_buf *buf)
@ -294,7 +294,7 @@ void ocmem_free(struct ocmem *ocmem, enum ocmem_client client,
clear_bit_unlock(BIT(client), &ocmem->active_allocations);
}
EXPORT_SYMBOL(ocmem_free);
EXPORT_SYMBOL_GPL(ocmem_free);
static int ocmem_dev_probe(struct platform_device *pdev)
{
@ -416,14 +416,12 @@ err_clk_disable:
return ret;
}
static int ocmem_dev_remove(struct platform_device *pdev)
static void ocmem_dev_remove(struct platform_device *pdev)
{
struct ocmem *ocmem = platform_get_drvdata(pdev);
clk_disable_unprepare(ocmem->core_clk);
clk_disable_unprepare(ocmem->iface_clk);
return 0;
}
static const struct ocmem_config ocmem_8226_config = {
@ -446,7 +444,7 @@ MODULE_DEVICE_TABLE(of, ocmem_of_match);
static struct platform_driver ocmem_driver = {
.probe = ocmem_dev_probe,
.remove = ocmem_dev_remove,
.remove_new = ocmem_dev_remove,
.driver = {
.name = "ocmem",
.of_match_table = ocmem_of_match,

View File

@ -554,7 +554,7 @@ err:
kfree(pds);
return ERR_PTR(ret);
}
EXPORT_SYMBOL(pdr_add_lookup);
EXPORT_SYMBOL_GPL(pdr_add_lookup);
/**
* pdr_restart_pd() - restart PD
@ -634,7 +634,7 @@ int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds)
return 0;
}
EXPORT_SYMBOL(pdr_restart_pd);
EXPORT_SYMBOL_GPL(pdr_restart_pd);
/**
* pdr_handle_alloc() - initialize the PDR client handle
@ -715,7 +715,7 @@ free_pdr_handle:
return ERR_PTR(ret);
}
EXPORT_SYMBOL(pdr_handle_alloc);
EXPORT_SYMBOL_GPL(pdr_handle_alloc);
/**
* pdr_handle_release() - release the PDR client handle
@ -749,7 +749,7 @@ void pdr_handle_release(struct pdr_handle *pdr)
kfree(pdr);
}
EXPORT_SYMBOL(pdr_handle_release);
EXPORT_SYMBOL_GPL(pdr_handle_release);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers");

View File

@ -318,7 +318,7 @@ out_release_ucsi_aux:
return ret;
}
static int pmic_glink_remove(struct platform_device *pdev)
static void pmic_glink_remove(struct platform_device *pdev)
{
struct pmic_glink *pg = dev_get_drvdata(&pdev->dev);
@ -334,8 +334,6 @@ static int pmic_glink_remove(struct platform_device *pdev)
mutex_lock(&__pmic_glink_lock);
__pmic_glink = NULL;
mutex_unlock(&__pmic_glink_lock);
return 0;
}
static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
@ -352,7 +350,7 @@ MODULE_DEVICE_TABLE(of, pmic_glink_of_match);
static struct platform_driver pmic_glink_driver = {
.probe = pmic_glink_probe,
.remove = pmic_glink_remove,
.remove_new = pmic_glink_remove,
.driver = {
.name = "qcom_pmic_glink",
.of_match_table = pmic_glink_of_match,

View File

@ -444,6 +444,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
ret = fwnode_property_read_u32(fwnode, "reg", &port);
if (ret < 0) {
dev_err(dev, "missing reg property of %pOFn\n", fwnode);
fwnode_handle_put(fwnode);
return ret;
}
@ -454,6 +455,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
if (altmode->ports[port].altmode) {
dev_err(dev, "multiple connector definition for port %u\n", port);
fwnode_handle_put(fwnode);
return -EINVAL;
}
@ -468,45 +470,59 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev,
alt_port->bridge.type = DRM_MODE_CONNECTOR_USB;
ret = devm_drm_bridge_add(dev, &alt_port->bridge);
if (ret)
if (ret) {
fwnode_handle_put(fwnode);
return ret;
}
alt_port->dp_alt.svid = USB_TYPEC_DP_SID;
alt_port->dp_alt.mode = USB_TYPEC_DP_MODE;
alt_port->dp_alt.active = 1;
alt_port->typec_mux = fwnode_typec_mux_get(fwnode);
if (IS_ERR(alt_port->typec_mux))
if (IS_ERR(alt_port->typec_mux)) {
fwnode_handle_put(fwnode);
return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux),
"failed to acquire mode-switch for port: %d\n",
port);
}
ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux,
alt_port->typec_mux);
if (ret)
if (ret) {
fwnode_handle_put(fwnode);
return ret;
}
alt_port->typec_retimer = fwnode_typec_retimer_get(fwnode);
if (IS_ERR(alt_port->typec_retimer))
if (IS_ERR(alt_port->typec_retimer)) {
fwnode_handle_put(fwnode);
return dev_err_probe(dev, PTR_ERR(alt_port->typec_retimer),
"failed to acquire retimer-switch for port: %d\n",
port);
}
ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_retimer,
alt_port->typec_retimer);
if (ret)
if (ret) {
fwnode_handle_put(fwnode);
return ret;
}
alt_port->typec_switch = fwnode_typec_switch_get(fwnode);
if (IS_ERR(alt_port->typec_switch))
if (IS_ERR(alt_port->typec_switch)) {
fwnode_handle_put(fwnode);
return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch),
"failed to acquire orientation-switch for port: %d\n",
port);
}
ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch,
alt_port->typec_switch);
if (ret)
if (ret) {
fwnode_handle_put(fwnode);
return ret;
}
}
altmode->client = devm_pmic_glink_register_client(dev,

View File

@ -199,7 +199,7 @@ u32 geni_se_get_qup_hw_version(struct geni_se *se)
return readl_relaxed(wrapper->base + QUP_HW_VER_REG);
}
EXPORT_SYMBOL(geni_se_get_qup_hw_version);
EXPORT_SYMBOL_GPL(geni_se_get_qup_hw_version);
static void geni_se_io_set_mode(void __iomem *base)
{
@ -272,7 +272,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr)
val |= S_COMMON_GENI_S_IRQ_EN;
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
}
EXPORT_SYMBOL(geni_se_init);
EXPORT_SYMBOL_GPL(geni_se_init);
static void geni_se_select_fifo_mode(struct geni_se *se)
{
@ -364,7 +364,7 @@ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
break;
}
}
EXPORT_SYMBOL(geni_se_select_mode);
EXPORT_SYMBOL_GPL(geni_se_select_mode);
/**
* DOC: Overview
@ -481,7 +481,7 @@ void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words,
if (pack_words || bpw == 32)
writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN);
}
EXPORT_SYMBOL(geni_se_config_packing);
EXPORT_SYMBOL_GPL(geni_se_config_packing);
static void geni_se_clks_off(struct geni_se *se)
{
@ -512,7 +512,7 @@ int geni_se_resources_off(struct geni_se *se)
geni_se_clks_off(se);
return 0;
}
EXPORT_SYMBOL(geni_se_resources_off);
EXPORT_SYMBOL_GPL(geni_se_resources_off);
static int geni_se_clks_on(struct geni_se *se)
{
@ -553,7 +553,7 @@ int geni_se_resources_on(struct geni_se *se)
return ret;
}
EXPORT_SYMBOL(geni_se_resources_on);
EXPORT_SYMBOL_GPL(geni_se_resources_on);
/**
* geni_se_clk_tbl_get() - Get the clock table to program DFS
@ -594,7 +594,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
*tbl = se->clk_perf_tbl;
return se->num_clk_levels;
}
EXPORT_SYMBOL(geni_se_clk_tbl_get);
EXPORT_SYMBOL_GPL(geni_se_clk_tbl_get);
/**
* geni_se_clk_freq_match() - Get the matching or closest SE clock frequency
@ -656,7 +656,7 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
return 0;
}
EXPORT_SYMBOL(geni_se_clk_freq_match);
EXPORT_SYMBOL_GPL(geni_se_clk_freq_match);
#define GENI_SE_DMA_DONE_EN BIT(0)
#define GENI_SE_DMA_EOT_EN BIT(1)
@ -684,7 +684,7 @@ void geni_se_tx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
writel(len, se->base + SE_DMA_TX_LEN);
}
EXPORT_SYMBOL(geni_se_tx_init_dma);
EXPORT_SYMBOL_GPL(geni_se_tx_init_dma);
/**
* geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer
@ -712,7 +712,7 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
geni_se_tx_init_dma(se, *iova, len);
return 0;
}
EXPORT_SYMBOL(geni_se_tx_dma_prep);
EXPORT_SYMBOL_GPL(geni_se_tx_dma_prep);
/**
* geni_se_rx_init_dma() - Initiate RX DMA transfer on the serial engine
@ -736,7 +736,7 @@ void geni_se_rx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len)
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
writel(len, se->base + SE_DMA_RX_LEN);
}
EXPORT_SYMBOL(geni_se_rx_init_dma);
EXPORT_SYMBOL_GPL(geni_se_rx_init_dma);
/**
* geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer
@ -764,7 +764,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
geni_se_rx_init_dma(se, *iova, len);
return 0;
}
EXPORT_SYMBOL(geni_se_rx_dma_prep);
EXPORT_SYMBOL_GPL(geni_se_rx_dma_prep);
/**
* geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer
@ -781,7 +781,7 @@ void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE);
}
EXPORT_SYMBOL(geni_se_tx_dma_unprep);
EXPORT_SYMBOL_GPL(geni_se_tx_dma_unprep);
/**
* geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer
@ -798,7 +798,7 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE);
}
EXPORT_SYMBOL(geni_se_rx_dma_unprep);
EXPORT_SYMBOL_GPL(geni_se_rx_dma_unprep);
int geni_icc_get(struct geni_se *se, const char *icc_ddr)
{
@ -827,7 +827,7 @@ err:
return err;
}
EXPORT_SYMBOL(geni_icc_get);
EXPORT_SYMBOL_GPL(geni_icc_get);
int geni_icc_set_bw(struct geni_se *se)
{
@ -845,7 +845,7 @@ int geni_icc_set_bw(struct geni_se *se)
return 0;
}
EXPORT_SYMBOL(geni_icc_set_bw);
EXPORT_SYMBOL_GPL(geni_icc_set_bw);
void geni_icc_set_tag(struct geni_se *se, u32 tag)
{
@ -854,7 +854,7 @@ void geni_icc_set_tag(struct geni_se *se, u32 tag)
for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++)
icc_set_tag(se->icc_paths[i].path, tag);
}
EXPORT_SYMBOL(geni_icc_set_tag);
EXPORT_SYMBOL_GPL(geni_icc_set_tag);
/* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */
int geni_icc_enable(struct geni_se *se)
@ -872,7 +872,7 @@ int geni_icc_enable(struct geni_se *se)
return 0;
}
EXPORT_SYMBOL(geni_icc_enable);
EXPORT_SYMBOL_GPL(geni_icc_enable);
int geni_icc_disable(struct geni_se *se)
{
@ -889,7 +889,7 @@ int geni_icc_disable(struct geni_se *se)
return 0;
}
EXPORT_SYMBOL(geni_icc_disable);
EXPORT_SYMBOL_GPL(geni_icc_disable);
static int geni_se_probe(struct platform_device *pdev)
{

View File

@ -260,7 +260,7 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...)
return ret;
}
EXPORT_SYMBOL(qmp_send);
EXPORT_SYMBOL_GPL(qmp_send);
static int qmp_qdss_clk_prepare(struct clk_hw *hw)
{
@ -458,7 +458,7 @@ struct qmp *qmp_get(struct device *dev)
}
return qmp;
}
EXPORT_SYMBOL(qmp_get);
EXPORT_SYMBOL_GPL(qmp_get);
/**
* qmp_put() - release a qmp handle
@ -473,7 +473,7 @@ void qmp_put(struct qmp *qmp)
if (!IS_ERR_OR_NULL(qmp))
put_device(qmp->dev);
}
EXPORT_SYMBOL(qmp_put);
EXPORT_SYMBOL_GPL(qmp_put);
static int qmp_probe(struct platform_device *pdev)
{
@ -533,7 +533,7 @@ err_free_mbox:
return ret;
}
static int qmp_remove(struct platform_device *pdev)
static void qmp_remove(struct platform_device *pdev)
{
struct qmp *qmp = platform_get_drvdata(pdev);
@ -542,8 +542,6 @@ static int qmp_remove(struct platform_device *pdev)
qmp_close(qmp);
mbox_free_channel(qmp->mbox_chan);
return 0;
}
static const struct of_device_id qmp_dt_match[] = {
@ -565,7 +563,7 @@ static struct platform_driver qmp_driver = {
.suppress_bind_attrs = true,
},
.probe = qmp_probe,
.remove = qmp_remove,
.remove_new = qmp_remove,
};
module_platform_driver(qmp_driver);

View File

@ -212,13 +212,11 @@ static int gsbi_probe(struct platform_device *pdev)
return of_platform_populate(node, NULL, NULL, &pdev->dev);
}
static int gsbi_remove(struct platform_device *pdev)
static void gsbi_remove(struct platform_device *pdev)
{
struct gsbi_info *gsbi = platform_get_drvdata(pdev);
clk_disable_unprepare(gsbi->hclk);
return 0;
}
static const struct of_device_id gsbi_dt_match[] = {
@ -234,7 +232,7 @@ static struct platform_driver gsbi_driver = {
.of_match_table = gsbi_dt_match,
},
.probe = gsbi_probe,
.remove = gsbi_remove,
.remove_new = gsbi_remove,
};
module_platform_driver(gsbi_driver);

View File

@ -216,13 +216,11 @@ static int qcom_stats_probe(struct platform_device *pdev)
return 0;
}
static int qcom_stats_remove(struct platform_device *pdev)
static void qcom_stats_remove(struct platform_device *pdev)
{
struct dentry *root = platform_get_drvdata(pdev);
debugfs_remove_recursive(root);
return 0;
}
static const struct stats_config rpm_data = {
@ -272,7 +270,7 @@ MODULE_DEVICE_TABLE(of, qcom_stats_table);
static struct platform_driver qcom_stats = {
.probe = qcom_stats_probe,
.remove = qcom_stats_remove,
.remove_new = qcom_stats_remove,
.driver = {
.name = "qcom_stats",
.of_match_table = qcom_stats_table,

View File

@ -754,7 +754,7 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
return msg;
}
EXPORT_SYMBOL(qmi_encode_message);
EXPORT_SYMBOL_GPL(qmi_encode_message);
/**
* qmi_decode_message() - Decode QMI encoded message to C structure
@ -778,7 +778,7 @@ int qmi_decode_message(const void *buf, size_t len,
return qmi_decode(ei, c_struct, buf + sizeof(struct qmi_header),
len - sizeof(struct qmi_header), 1);
}
EXPORT_SYMBOL(qmi_decode_message);
EXPORT_SYMBOL_GPL(qmi_decode_message);
/* Common header in all QMI responses */
const struct qmi_elem_info qmi_response_type_v01_ei[] = {
@ -810,7 +810,7 @@ const struct qmi_elem_info qmi_response_type_v01_ei[] = {
.ei_array = NULL,
},
};
EXPORT_SYMBOL(qmi_response_type_v01_ei);
EXPORT_SYMBOL_GPL(qmi_response_type_v01_ei);
MODULE_DESCRIPTION("QMI encoder/decoder helper");
MODULE_LICENSE("GPL v2");

View File

@ -223,7 +223,7 @@ int qmi_add_lookup(struct qmi_handle *qmi, unsigned int service,
return 0;
}
EXPORT_SYMBOL(qmi_add_lookup);
EXPORT_SYMBOL_GPL(qmi_add_lookup);
static void qmi_send_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
{
@ -287,7 +287,7 @@ int qmi_add_server(struct qmi_handle *qmi, unsigned int service,
return 0;
}
EXPORT_SYMBOL(qmi_add_server);
EXPORT_SYMBOL_GPL(qmi_add_server);
/**
* qmi_txn_init() - allocate transaction id within the given QMI handle
@ -328,7 +328,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn,
return ret;
}
EXPORT_SYMBOL(qmi_txn_init);
EXPORT_SYMBOL_GPL(qmi_txn_init);
/**
* qmi_txn_wait() - wait for a response on a transaction
@ -359,7 +359,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
else
return txn->result;
}
EXPORT_SYMBOL(qmi_txn_wait);
EXPORT_SYMBOL_GPL(qmi_txn_wait);
/**
* qmi_txn_cancel() - cancel an ongoing transaction
@ -375,7 +375,7 @@ void qmi_txn_cancel(struct qmi_txn *txn)
mutex_unlock(&txn->lock);
mutex_unlock(&qmi->txn_lock);
}
EXPORT_SYMBOL(qmi_txn_cancel);
EXPORT_SYMBOL_GPL(qmi_txn_cancel);
/**
* qmi_invoke_handler() - find and invoke a handler for a message
@ -676,7 +676,7 @@ err_free_recv_buf:
return ret;
}
EXPORT_SYMBOL(qmi_handle_init);
EXPORT_SYMBOL_GPL(qmi_handle_init);
/**
* qmi_handle_release() - release the QMI client handle
@ -717,7 +717,7 @@ void qmi_handle_release(struct qmi_handle *qmi)
kfree(svc);
}
}
EXPORT_SYMBOL(qmi_handle_release);
EXPORT_SYMBOL_GPL(qmi_handle_release);
/**
* qmi_send_message() - send a QMI message
@ -796,7 +796,7 @@ ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return qmi_send_message(qmi, sq, txn, QMI_REQUEST, msg_id, len, ei,
c_struct);
}
EXPORT_SYMBOL(qmi_send_request);
EXPORT_SYMBOL_GPL(qmi_send_request);
/**
* qmi_send_response() - send a response QMI message
@ -817,7 +817,7 @@ ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return qmi_send_message(qmi, sq, txn, QMI_RESPONSE, msg_id, len, ei,
c_struct);
}
EXPORT_SYMBOL(qmi_send_response);
EXPORT_SYMBOL_GPL(qmi_send_response);
/**
* qmi_send_indication() - send an indication QMI message
@ -851,4 +851,4 @@ ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
return rval;
}
EXPORT_SYMBOL(qmi_send_indication);
EXPORT_SYMBOL_GPL(qmi_send_indication);

View File

@ -200,6 +200,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
rmtfs_mem->client_id = client_id;
rmtfs_mem->size = rmem->size;
/*
* If requested, discard the first and last 4k block in order to ensure
* that the rmtfs region isn't adjacent to other protected regions.
*/
if (of_property_read_bool(node, "qcom,use-guard-pages")) {
rmtfs_mem->addr += SZ_4K;
rmtfs_mem->size -= 2 * SZ_4K;
}
device_initialize(&rmtfs_mem->dev);
rmtfs_mem->dev.parent = &pdev->dev;
rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups;
@ -281,7 +290,7 @@ put_device:
return ret;
}
static int qcom_rmtfs_mem_remove(struct platform_device *pdev)
static void qcom_rmtfs_mem_remove(struct platform_device *pdev)
{
struct qcom_rmtfs_mem *rmtfs_mem = dev_get_drvdata(&pdev->dev);
struct qcom_scm_vmperm perm;
@ -296,8 +305,6 @@ static int qcom_rmtfs_mem_remove(struct platform_device *pdev)
cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev);
put_device(&rmtfs_mem->dev);
return 0;
}
static const struct of_device_id qcom_rmtfs_mem_of_match[] = {
@ -308,7 +315,7 @@ MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match);
static struct platform_driver qcom_rmtfs_mem_driver = {
.probe = qcom_rmtfs_mem_probe,
.remove = qcom_rmtfs_mem_remove,
.remove_new = qcom_rmtfs_mem_remove,
.driver = {
.name = "qcom_rmtfs_mem",
.of_match_table = qcom_rmtfs_mem_of_match,

View File

@ -239,7 +239,7 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state,
return __rpmh_write(dev, state, rpm_msg);
}
EXPORT_SYMBOL(rpmh_write_async);
EXPORT_SYMBOL_GPL(rpmh_write_async);
/**
* rpmh_write: Write a set of RPMH commands and block until response
@ -270,7 +270,7 @@ int rpmh_write(const struct device *dev, enum rpmh_state state,
WARN_ON(!ret);
return (ret > 0) ? 0 : -ETIMEDOUT;
}
EXPORT_SYMBOL(rpmh_write);
EXPORT_SYMBOL_GPL(rpmh_write);
static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
{
@ -395,7 +395,7 @@ exit:
return ret;
}
EXPORT_SYMBOL(rpmh_write_batch);
EXPORT_SYMBOL_GPL(rpmh_write_batch);
static int is_req_valid(struct cache_req *req)
{
@ -500,4 +500,4 @@ void rpmh_invalidate(const struct device *dev)
ctrlr->dirty = true;
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
}
EXPORT_SYMBOL(rpmh_invalidate);
EXPORT_SYMBOL_GPL(rpmh_invalidate);

View File

@ -142,7 +142,7 @@ out:
mutex_unlock(&rpm->lock);
return ret;
}
EXPORT_SYMBOL(qcom_rpm_smd_write);
EXPORT_SYMBOL_GPL(qcom_rpm_smd_write);
static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev,
void *data,

View File

@ -285,7 +285,7 @@ struct qcom_smem {
struct smem_partition partitions[SMEM_HOST_COUNT];
unsigned num_regions;
struct smem_region regions[];
struct smem_region regions[] __counted_by(num_regions);
};
static void *
@ -368,7 +368,7 @@ bool qcom_smem_is_available(void)
{
return !!__smem;
}
EXPORT_SYMBOL(qcom_smem_is_available);
EXPORT_SYMBOL_GPL(qcom_smem_is_available);
static int qcom_smem_alloc_private(struct qcom_smem *smem,
struct smem_partition *part,
@ -1187,14 +1187,12 @@ static int qcom_smem_probe(struct platform_device *pdev)
return 0;
}
static int qcom_smem_remove(struct platform_device *pdev)
static void qcom_smem_remove(struct platform_device *pdev)
{
platform_device_unregister(__smem->socinfo);
hwspin_lock_free(__smem->hwlock);
__smem = NULL;
return 0;
}
static const struct of_device_id qcom_smem_of_match[] = {
@ -1205,7 +1203,7 @@ MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
static struct platform_driver qcom_smem_driver = {
.probe = qcom_smem_probe,
.remove = qcom_smem_remove,
.remove_new = qcom_smem_remove,
.driver = {
.name = "qcom-smem",
.of_match_table = qcom_smem_of_match,

View File

@ -660,7 +660,7 @@ report_read_failure:
return -EINVAL;
}
static int qcom_smp2p_remove(struct platform_device *pdev)
static void qcom_smp2p_remove(struct platform_device *pdev)
{
struct qcom_smp2p *smp2p = platform_get_drvdata(pdev);
struct smp2p_entry *entry;
@ -676,8 +676,6 @@ static int qcom_smp2p_remove(struct platform_device *pdev)
mbox_free_channel(smp2p->mbox_chan);
smp2p->out->valid_entries = 0;
return 0;
}
static const struct of_device_id qcom_smp2p_of_match[] = {
@ -688,7 +686,7 @@ MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match);
static struct platform_driver qcom_smp2p_driver = {
.probe = qcom_smp2p_probe,
.remove = qcom_smp2p_remove,
.remove_new = qcom_smp2p_remove,
.driver = {
.name = "qcom_smp2p",
.of_match_table = qcom_smp2p_of_match,

View File

@ -613,7 +613,7 @@ out_put:
return ret;
}
static int qcom_smsm_remove(struct platform_device *pdev)
static void qcom_smsm_remove(struct platform_device *pdev)
{
struct qcom_smsm *smsm = platform_get_drvdata(pdev);
unsigned id;
@ -623,8 +623,6 @@ static int qcom_smsm_remove(struct platform_device *pdev)
irq_domain_remove(smsm->entries[id].domain);
qcom_smem_state_unregister(smsm->state);
return 0;
}
static const struct of_device_id qcom_smsm_of_match[] = {
@ -635,7 +633,7 @@ MODULE_DEVICE_TABLE(of, qcom_smsm_of_match);
static struct platform_driver qcom_smsm_driver = {
.probe = qcom_smsm_probe,
.remove = qcom_smsm_remove,
.remove_new = qcom_smsm_remove,
.driver = {
.name = "qcom-smsm",
.of_match_table = qcom_smsm_of_match,

View File

@ -117,6 +117,12 @@ static const char *const pmic_models[] = {
[55] = "PM2250",
[58] = "PM8450",
[65] = "PM8010",
[69] = "PM8550VS",
[70] = "PM8550VE",
[71] = "PM8550B",
[72] = "PMR735D",
[73] = "PM8550",
[74] = "PMK8550",
};
struct socinfo_params {
@ -349,6 +355,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SDA439) },
{ qcom_board_id(SDA429) },
{ qcom_board_id(SM7150) },
{ qcom_board_id(SM7150P) },
{ qcom_board_id(IPQ8070) },
{ qcom_board_id(IPQ8071) },
{ qcom_board_id(QM215) },
@ -359,6 +366,9 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(SM6125) },
{ qcom_board_id(IPQ8070A) },
{ qcom_board_id(IPQ8071A) },
{ qcom_board_id(IPQ8172) },
{ qcom_board_id(IPQ8173) },
{ qcom_board_id(IPQ8174) },
{ qcom_board_id(IPQ6018) },
{ qcom_board_id(IPQ6028) },
{ qcom_board_id(SDM429W) },
@ -389,6 +399,7 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id_named(SM8450_3, "SM8450") },
{ qcom_board_id(SC7280) },
{ qcom_board_id(SC7180P) },
{ qcom_board_id(QCM6490) },
{ qcom_board_id(IPQ5000) },
{ qcom_board_id(IPQ0509) },
{ qcom_board_id(IPQ0518) },
@ -776,20 +787,18 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
return 0;
}
static int qcom_socinfo_remove(struct platform_device *pdev)
static void qcom_socinfo_remove(struct platform_device *pdev)
{
struct qcom_socinfo *qs = platform_get_drvdata(pdev);
soc_device_unregister(qs->soc_dev);
socinfo_debugfs_exit(qs);
return 0;
}
static struct platform_driver qcom_socinfo_driver = {
.probe = qcom_socinfo_probe,
.remove = qcom_socinfo_remove,
.remove_new = qcom_socinfo_remove,
.driver = {
.name = "qcom-socinfo",
},

View File

@ -287,7 +287,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
return rpmsg_create_ept(_wcnss->channel->rpdev, cb, priv, chinfo);
}
EXPORT_SYMBOL(qcom_wcnss_open_channel);
EXPORT_SYMBOL_GPL(qcom_wcnss_open_channel);
static void wcnss_async_probe(struct work_struct *work)
{
@ -355,7 +355,6 @@ static struct rpmsg_driver wcnss_ctrl_driver = {
.callback = wcnss_ctrl_smd_callback,
.drv = {
.name = "qcom_wcnss_ctrl",
.owner = THIS_MODULE,
.of_match_table = wcnss_ctrl_of_match,
},
};

View File

@ -193,6 +193,7 @@
#define QCOM_ID_SDA439 363
#define QCOM_ID_SDA429 364
#define QCOM_ID_SM7150 365
#define QCOM_ID_SM7150P 366
#define QCOM_ID_IPQ8070 375
#define QCOM_ID_IPQ8071 376
#define QCOM_ID_QM215 386
@ -203,6 +204,9 @@
#define QCOM_ID_SM6125 394
#define QCOM_ID_IPQ8070A 395
#define QCOM_ID_IPQ8071A 396
#define QCOM_ID_IPQ8172 397
#define QCOM_ID_IPQ8173 398
#define QCOM_ID_IPQ8174 399
#define QCOM_ID_IPQ6018 402
#define QCOM_ID_IPQ6028 403
#define QCOM_ID_SDM429W 416
@ -233,6 +237,7 @@
#define QCOM_ID_SM8450_3 482
#define QCOM_ID_SC7280 487
#define QCOM_ID_SC7180P 495
#define QCOM_ID_QCM6490 497
#define QCOM_ID_IPQ5000 503
#define QCOM_ID_IPQ0509 504
#define QCOM_ID_IPQ0518 505

View File

@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
* Responsible for setting up and managing QSEECOM client devices.
*
* Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/types.h>
#include <linux/firmware/qcom/qcom_scm.h>
/**
* struct qseecom_client - QSEECOM client device.
* @aux_dev: Underlying auxiliary device.
* @app_id: ID of the loaded application.
*/
struct qseecom_client {
struct auxiliary_device aux_dev;
u32 app_id;
};
/**
* qcom_qseecom_app_send() - Send to and receive data from a given QSEE app.
* @client: The QSEECOM client associated with the target app.
* @req: Request buffer sent to the app (must be DMA-mappable).
* @req_size: Size of the request buffer.
* @rsp: Response buffer, written to by the app (must be DMA-mappable).
* @rsp_size: Size of the response buffer.
*
* Sends a request to the QSEE app associated with the given client and read
* back its response. The caller must provide two DMA memory regions, one for
* the request and one for the response, and fill out the @req region with the
* respective (app-specific) request data. The QSEE app reads this and returns
* its response in the @rsp region.
*
* Note: This is a convenience wrapper around qcom_scm_qseecom_app_send().
* Clients should prefer to use this wrapper.
*
* Return: Zero on success, nonzero on failure.
*/
static inline int qcom_qseecom_app_send(struct qseecom_client *client, void *req, size_t req_size,
void *rsp, size_t rsp_size)
{
return qcom_scm_qseecom_app_send(client->app_id, req, req_size, rsp, rsp_size);
}

View File

@ -59,12 +59,12 @@ enum qcom_scm_ice_cipher {
#define QCOM_SCM_PERM_RW (QCOM_SCM_PERM_READ | QCOM_SCM_PERM_WRITE)
#define QCOM_SCM_PERM_RWX (QCOM_SCM_PERM_RW | QCOM_SCM_PERM_EXEC)
extern bool qcom_scm_is_available(void);
bool qcom_scm_is_available(void);
extern int qcom_scm_set_cold_boot_addr(void *entry);
extern int qcom_scm_set_warm_boot_addr(void *entry);
extern void qcom_scm_cpu_power_down(u32 flags);
extern int qcom_scm_set_remote_state(u32 state, u32 id);
int qcom_scm_set_cold_boot_addr(void *entry);
int qcom_scm_set_warm_boot_addr(void *entry);
void qcom_scm_cpu_power_down(u32 flags);
int qcom_scm_set_remote_state(u32 state, u32 id);
struct qcom_scm_pas_metadata {
void *ptr;
@ -72,54 +72,69 @@ struct qcom_scm_pas_metadata {
ssize_t size;
};
extern int qcom_scm_pas_init_image(u32 peripheral, const void *metadata,
size_t size,
struct qcom_scm_pas_metadata *ctx);
extern void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx);
extern int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr,
phys_addr_t size);
extern int qcom_scm_pas_auth_and_reset(u32 peripheral);
extern int qcom_scm_pas_shutdown(u32 peripheral);
extern bool qcom_scm_pas_supported(u32 peripheral);
int qcom_scm_pas_init_image(u32 peripheral, const void *metadata, size_t size,
struct qcom_scm_pas_metadata *ctx);
void qcom_scm_pas_metadata_release(struct qcom_scm_pas_metadata *ctx);
int qcom_scm_pas_mem_setup(u32 peripheral, phys_addr_t addr, phys_addr_t size);
int qcom_scm_pas_auth_and_reset(u32 peripheral);
int qcom_scm_pas_shutdown(u32 peripheral);
bool qcom_scm_pas_supported(u32 peripheral);
extern int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
extern int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
int qcom_scm_io_readl(phys_addr_t addr, unsigned int *val);
int qcom_scm_io_writel(phys_addr_t addr, unsigned int val);
extern bool qcom_scm_restore_sec_cfg_available(void);
extern int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
extern int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
extern int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
extern int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size);
extern int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
u32 cp_nonpixel_start,
u32 cp_nonpixel_size);
extern int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
u64 *src,
const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt);
bool qcom_scm_restore_sec_cfg_available(void);
int qcom_scm_restore_sec_cfg(u32 device_id, u32 spare);
int qcom_scm_iommu_secure_ptbl_size(u32 spare, size_t *size);
int qcom_scm_iommu_secure_ptbl_init(u64 addr, u32 size, u32 spare);
int qcom_scm_iommu_set_cp_pool_size(u32 spare, u32 size);
int qcom_scm_mem_protect_video_var(u32 cp_start, u32 cp_size,
u32 cp_nonpixel_start, u32 cp_nonpixel_size);
int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz, u64 *src,
const struct qcom_scm_vmperm *newvm,
unsigned int dest_cnt);
extern bool qcom_scm_ocmem_lock_available(void);
extern int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size, u32 mode);
extern int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset,
u32 size);
bool qcom_scm_ocmem_lock_available(void);
int qcom_scm_ocmem_lock(enum qcom_scm_ocmem_client id, u32 offset, u32 size,
u32 mode);
int qcom_scm_ocmem_unlock(enum qcom_scm_ocmem_client id, u32 offset, u32 size);
extern bool qcom_scm_ice_available(void);
extern int qcom_scm_ice_invalidate_key(u32 index);
extern int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
enum qcom_scm_ice_cipher cipher,
u32 data_unit_size);
bool qcom_scm_ice_available(void);
int qcom_scm_ice_invalidate_key(u32 index);
int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
enum qcom_scm_ice_cipher cipher, u32 data_unit_size);
extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
bool qcom_scm_hdcp_available(void);
int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp);
extern int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt);
extern int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
int qcom_scm_iommu_set_pt_format(u32 sec_id, u32 ctx_num, u32 pt_fmt);
int qcom_scm_qsmmu500_wait_safe_toggle(bool en);
extern int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,
u64 limit_node, u32 node_id, u64 version);
extern int qcom_scm_lmh_profile_change(u32 profile_id);
extern bool qcom_scm_lmh_dcvsh_available(void);
int qcom_scm_lmh_dcvsh(u32 payload_fn, u32 payload_reg, u32 payload_val,
u64 limit_node, u32 node_id, u64 version);
int qcom_scm_lmh_profile_change(u32 profile_id);
bool qcom_scm_lmh_dcvsh_available(void);
#ifdef CONFIG_QCOM_QSEECOM
int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id);
int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp,
size_t rsp_size);
#else /* CONFIG_QCOM_QSEECOM */
static inline int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id)
{
return -EINVAL;
}
static inline int qcom_scm_qseecom_app_send(u32 app_id, void *req,
size_t req_size, void *rsp,
size_t rsp_size)
{
return -EINVAL;
}
#endif /* CONFIG_QCOM_QSEECOM */
#endif

View File

@ -127,6 +127,12 @@ static inline int nvmem_cell_write(struct nvmem_cell *cell,
return -EOPNOTSUPP;
}
static inline int nvmem_cell_read_u8(struct device *dev,
const char *cell_id, u8 *val)
{
return -EOPNOTSUPP;
}
static inline int nvmem_cell_read_u16(struct device *dev,
const char *cell_id, u16 *val)
{

View File

@ -30,7 +30,7 @@
#define LLCC_NPU 23
#define LLCC_WLHW 24
#define LLCC_PIMEM 25
#define LLCC_DRE 26
#define LLCC_ECC 26
#define LLCC_CVP 28
#define LLCC_MODPE 29
#define LLCC_APTCM 30

View File

@ -10,6 +10,7 @@ typedef u16 ucs2_char_t;
unsigned long ucs2_strnlen(const ucs2_char_t *s, size_t maxlength);
unsigned long ucs2_strlen(const ucs2_char_t *s);
unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count);
int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);
unsigned long ucs2_utf8size(const ucs2_char_t *src);

View File

@ -32,6 +32,58 @@ ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
}
EXPORT_SYMBOL(ucs2_strsize);
/**
* ucs2_strscpy() - Copy a UCS2 string into a sized buffer.
*
* @dst: Pointer to the destination buffer where to copy the string to.
* @src: Pointer to the source buffer where to copy the string from.
* @count: Size of the destination buffer, in UCS2 (16-bit) characters.
*
* Like strscpy(), only for UCS2 strings.
*
* Copy the source string @src, or as much of it as fits, into the destination
* buffer @dst. The behavior is undefined if the string buffers overlap. The
* destination buffer @dst is always NUL-terminated, unless it's zero-sized.
*
* Return: The number of characters copied into @dst (excluding the trailing
* %NUL terminator) or -E2BIG if @count is 0 or @src was truncated due to the
* destination buffer being too small.
*/
ssize_t ucs2_strscpy(ucs2_char_t *dst, const ucs2_char_t *src, size_t count)
{
long res;
/*
* Ensure that we have a valid amount of space. We need to store at
* least one NUL-character.
*/
if (count == 0 || WARN_ON_ONCE(count > INT_MAX / sizeof(*dst)))
return -E2BIG;
/*
* Copy at most 'count' characters, return early if we find a
* NUL-terminator.
*/
for (res = 0; res < count; res++) {
ucs2_char_t c;
c = src[res];
dst[res] = c;
if (!c)
return res;
}
/*
* The loop above terminated without finding a NUL-terminator,
* exceeding the 'count': Enforce proper NUL-termination and return
* error.
*/
dst[count - 1] = 0;
return -E2BIG;
}
EXPORT_SYMBOL(ucs2_strscpy);
int
ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
{