mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 21:24:08 +08:00
Qualcomm ARM Based Driver Updates for v4.18
* Various SMEM updates/fixes * Add qcom_smem_virt_to_phys SMEM API * Update MAINTAINERS to include qcom_scm pattern * Add Qualcomm Command DB driver * Add Qualcomm SCM compatible for IPQ4019 * Add MSM8998 to smd-rpm compatible list * Add Qualcomm GENI based QUP wrapper * Fix Qualcomm QMI buffer sizing bug -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJbCHgwAAoJEFKiBbHx2RXVUHEP+wWnlsXvaoT50PRavwcW2Gbk OLWpWWeh90TRtuW9IZ+VXUhClVSvSBi+M46xKqO2M/0WumNRRE4dZDL3DjSqOBVZ 2MQP+uhfviv5GqpEuPq18luedV6S0orsQY+FLmqD4+/vHW8oXUvC1m2iqsYkst27 gtPYSiuVZkJDc0pvPzsFDFL5WBQ84W4ki2Jsc2xuf0clUxASoOfT8/RFyZ1M3suV R9hzOUCWY1+c+YZbvYyPTLu1Y20ksHcnfnhAc/ZUxGyzIWLX30XWjc26pJbF8eRU EJiI0pyPkzue4GokrWI1H9AOgmSoJjdMFg0uvz3Y6opreKJi5+GSiVZeojU7/e5a yNhrdF6R9jp5n/jwvql7yiMHwxiv8dzuSvvlQCJfEMVZBD2maPAojiXXOFs06pNg WdhKFO5x4XH+kkiUnDs7sXpT/Szd1Eqr9wsIxLj9pbH++0Z5TYpOjFkE948fiLa9 QUywzT4TLD5/N4z4iIsE8Xd4Zm+jxlQ/1AEouegntkav0UgCeJsHlijGl2T5xrPC NDRSUpABI6Ypf+mDlxsVI+9WZm7o7PTAVUVnOrKF7FRZRNdGOLsrV0f5awJuyBgf XfhsOUm6IB3vzON2TrvVno7Fa4vdOFFGZsTbn8hdW2YSDpgLmebHZg20hAjXrImd 8VB7e4tK0yPtweUfIg9U =hFnt -----END PGP SIGNATURE----- Merge tag 'qcom-drivers-for-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/late Qualcomm ARM Based Driver Updates for v4.18 * Various SMEM updates/fixes * Add qcom_smem_virt_to_phys SMEM API * Update MAINTAINERS to include qcom_scm pattern * Add Qualcomm Command DB driver * Add Qualcomm SCM compatible for IPQ4019 * Add MSM8998 to smd-rpm compatible list * Add Qualcomm GENI based QUP wrapper * Fix Qualcomm QMI buffer sizing bug * tag 'qcom-drivers-for-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux: soc: qcom: smem: introduce qcom_smem_virt_to_phys() soc: qcom: qmi: fix a buffer sizing bug MAINTAINERS: Update pattern for qcom_scm soc: Unconditionally include qcom Makefile soc: qcom: smem: check sooner in qcom_smem_set_global_partition() soc: qcom: smem: fix qcom_smem_set_global_partition() soc: qcom: smem: fix off-by-one error in qcom_smem_alloc_private() soc: qcom: smem: byte swap values properly soc: qcom: smem: return proper type for cached entry functions soc: qcom: smem: fix first cache entry calculation soc: qcom: cmd-db: Make endian-agnostic drivers: qcom: add command DB driver soc: qcom: Add GENI based QUP Wrapper driver soc: qcom: smd-rpm: Add msm8998 compatible firmware: qcom: scm: Add ipq4019 soc compatible Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
ae709bf8ad
@ -11,9 +11,10 @@ Required properties:
|
||||
* "qcom,scm-msm8660" for MSM8660 platforms
|
||||
* "qcom,scm-msm8690" for MSM8690 platforms
|
||||
* "qcom,scm-msm8996" for MSM8996 platforms
|
||||
* "qcom,scm-ipq4019" for IPQ4019 platforms
|
||||
* "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc)
|
||||
- clocks: One to three clocks may be required based on compatible.
|
||||
* No clock required for "qcom,scm-msm8996"
|
||||
* No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019"
|
||||
* Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960"
|
||||
* Core, iface, and bus clocks required for "qcom,scm"
|
||||
- clock-names: Must contain "core" for the core clock, "iface" for the interface
|
||||
|
@ -22,6 +22,7 @@ resources.
|
||||
"qcom,rpm-apq8084"
|
||||
"qcom,rpm-msm8916"
|
||||
"qcom,rpm-msm8974"
|
||||
"qcom,rpm-msm8998"
|
||||
|
||||
- qcom,smd-channels:
|
||||
Usage: required
|
||||
|
@ -1817,7 +1817,7 @@ F: drivers/spi/spi-qup.c
|
||||
F: drivers/tty/serial/msm_serial.c
|
||||
F: drivers/*/pm8???-*
|
||||
F: drivers/mfd/ssbi.c
|
||||
F: drivers/firmware/qcom_scm.c
|
||||
F: drivers/firmware/qcom_scm*
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux.git
|
||||
|
||||
ARM/RADISYS ENP2611 MACHINE SUPPORT
|
||||
|
@ -603,6 +603,9 @@ static const struct of_device_id qcom_scm_dt_match[] = {
|
||||
{ .compatible = "qcom,scm-msm8996",
|
||||
.data = NULL, /* no clocks */
|
||||
},
|
||||
{ .compatible = "qcom,scm-ipq4019",
|
||||
.data = NULL, /* no clocks */
|
||||
},
|
||||
{ .compatible = "qcom,scm",
|
||||
.data = (void *)(SCM_HAS_CORE_CLK
|
||||
| SCM_HAS_IFACE_CLK
|
||||
|
@ -494,6 +494,7 @@ EXPORT_SYMBOL_GPL(of_platform_default_populate);
|
||||
#ifndef CONFIG_PPC
|
||||
static const struct of_device_id reserved_mem_matches[] = {
|
||||
{ .compatible = "qcom,rmtfs-mem" },
|
||||
{ .compatible = "qcom,cmd-db" },
|
||||
{ .compatible = "ramoops" },
|
||||
{}
|
||||
};
|
||||
|
@ -14,7 +14,7 @@ obj-$(CONFIG_ARCH_MXC) += imx/
|
||||
obj-$(CONFIG_SOC_XWAY) += lantiq/
|
||||
obj-y += mediatek/
|
||||
obj-$(CONFIG_ARCH_MESON) += amlogic/
|
||||
obj-$(CONFIG_ARCH_QCOM) += qcom/
|
||||
obj-y += qcom/
|
||||
obj-y += renesas/
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
|
||||
|
@ -3,6 +3,24 @@
|
||||
#
|
||||
menu "Qualcomm SoC drivers"
|
||||
|
||||
config QCOM_COMMAND_DB
|
||||
bool "Qualcomm Command DB"
|
||||
depends on (ARCH_QCOM && OF) || COMPILE_TEST
|
||||
help
|
||||
Command DB queries shared memory by key string for shared system
|
||||
resources. Platform drivers that require to set state of a shared
|
||||
resource on a RPM-hardened platform must use this database to get
|
||||
SoC specific identifier and information for the shared resources.
|
||||
|
||||
config QCOM_GENI_SE
|
||||
tristate "QCOM GENI Serial Engine Driver"
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
help
|
||||
This driver is used to manage Generic Interface (GENI) firmware based
|
||||
Qualcomm Technologies, Inc. Universal Peripheral (QUP) Wrapper. This
|
||||
driver is also used to manage the common aspects of multiple Serial
|
||||
Engines present in the QUP.
|
||||
|
||||
config QCOM_GLINK_SSR
|
||||
tristate "Qualcomm Glink SSR driver"
|
||||
depends on RPMSG
|
||||
|
@ -1,4 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_QCOM_GENI_SE) += qcom-geni-se.o
|
||||
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
|
||||
obj-$(CONFIG_QCOM_GLINK_SSR) += glink_ssr.o
|
||||
obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
|
||||
obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
|
||||
|
317
drivers/soc/qcom/cmd-db.c
Normal file
317
drivers/soc/qcom/cmd-db.c
Normal file
@ -0,0 +1,317 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/qcom/cmd-db.h>
|
||||
|
||||
#define NUM_PRIORITY 2
|
||||
#define MAX_SLV_ID 8
|
||||
#define SLAVE_ID_MASK 0x7
|
||||
#define SLAVE_ID_SHIFT 16
|
||||
|
||||
/**
|
||||
* struct entry_header: header for each entry in cmddb
|
||||
*
|
||||
* @id: resource's identifier
|
||||
* @priority: unused
|
||||
* @addr: the address of the resource
|
||||
* @len: length of the data
|
||||
* @offset: offset from :@data_offset, start of the data
|
||||
*/
|
||||
struct entry_header {
|
||||
u8 id[8];
|
||||
__le32 priority[NUM_PRIORITY];
|
||||
__le32 addr;
|
||||
__le16 len;
|
||||
__le16 offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rsc_hdr: resource header information
|
||||
*
|
||||
* @slv_id: id for the resource
|
||||
* @header_offset: entry's header at offset from the end of the cmd_db_header
|
||||
* @data_offset: entry's data at offset from the end of the cmd_db_header
|
||||
* @cnt: number of entries for HW type
|
||||
* @version: MSB is major, LSB is minor
|
||||
* @reserved: reserved for future use.
|
||||
*/
|
||||
struct rsc_hdr {
|
||||
__le16 slv_id;
|
||||
__le16 header_offset;
|
||||
__le16 data_offset;
|
||||
__le16 cnt;
|
||||
__le16 version;
|
||||
__le16 reserved[3];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cmd_db_header: The DB header information
|
||||
*
|
||||
* @version: The cmd db version
|
||||
* @magic: constant expected in the database
|
||||
* @header: array of resources
|
||||
* @checksum: checksum for the header. Unused.
|
||||
* @reserved: reserved memory
|
||||
* @data: driver specific data
|
||||
*/
|
||||
struct cmd_db_header {
|
||||
__le32 version;
|
||||
u8 magic[4];
|
||||
struct rsc_hdr header[MAX_SLV_ID];
|
||||
__le32 checksum;
|
||||
__le32 reserved;
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
/**
|
||||
* DOC: Description of the Command DB database.
|
||||
*
|
||||
* At the start of the command DB memory is the cmd_db_header structure.
|
||||
* The cmd_db_header holds the version, checksum, magic key as well as an
|
||||
* array for header for each slave (depicted by the rsc_header). Each h/w
|
||||
* based accelerator is a 'slave' (shared resource) and has slave id indicating
|
||||
* the type of accelerator. The rsc_header is the header for such individual
|
||||
* slaves of a given type. The entries for each of these slaves begin at the
|
||||
* rsc_hdr.header_offset. In addition each slave could have auxiliary data
|
||||
* that may be needed by the driver. The data for the slave starts at the
|
||||
* entry_header.offset to the location pointed to by the rsc_hdr.data_offset.
|
||||
*
|
||||
* Drivers have a stringified key to a slave/resource. They can query the slave
|
||||
* information and get the slave id and the auxiliary data and the length of the
|
||||
* data. Using this information, they can format the request to be sent to the
|
||||
* h/w accelerator and request a resource state.
|
||||
*/
|
||||
|
||||
static const u8 CMD_DB_MAGIC[] = { 0xdb, 0x30, 0x03, 0x0c };
|
||||
|
||||
static bool cmd_db_magic_matches(const struct cmd_db_header *header)
|
||||
{
|
||||
const u8 *magic = header->magic;
|
||||
|
||||
return memcmp(magic, CMD_DB_MAGIC, ARRAY_SIZE(CMD_DB_MAGIC)) == 0;
|
||||
}
|
||||
|
||||
static struct cmd_db_header *cmd_db_header;
|
||||
|
||||
|
||||
static inline void *rsc_to_entry_header(struct rsc_hdr *hdr)
|
||||
{
|
||||
u16 offset = le16_to_cpu(hdr->header_offset);
|
||||
|
||||
return cmd_db_header->data + offset;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent)
|
||||
{
|
||||
u16 offset = le16_to_cpu(hdr->data_offset);
|
||||
u16 loffset = le16_to_cpu(ent->offset);
|
||||
|
||||
return cmd_db_header->data + offset + loffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* cmd_db_ready - Indicates if command DB is available
|
||||
*
|
||||
* Return: 0 on success, errno otherwise
|
||||
*/
|
||||
int cmd_db_ready(void)
|
||||
{
|
||||
if (cmd_db_header == NULL)
|
||||
return -EPROBE_DEFER;
|
||||
else if (!cmd_db_magic_matches(cmd_db_header))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_ready);
|
||||
|
||||
static int cmd_db_get_header(const char *id, struct entry_header *eh,
|
||||
struct rsc_hdr *rh)
|
||||
{
|
||||
struct rsc_hdr *rsc_hdr;
|
||||
struct entry_header *ent;
|
||||
int ret, i, j;
|
||||
u8 query[8];
|
||||
|
||||
ret = cmd_db_ready();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!eh || !rh)
|
||||
return -EINVAL;
|
||||
|
||||
/* Pad out query string to same length as in DB */
|
||||
strncpy(query, id, sizeof(query));
|
||||
|
||||
for (i = 0; i < MAX_SLV_ID; i++) {
|
||||
rsc_hdr = &cmd_db_header->header[i];
|
||||
if (!rsc_hdr->slv_id)
|
||||
break;
|
||||
|
||||
ent = rsc_to_entry_header(rsc_hdr);
|
||||
for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) {
|
||||
if (memcmp(ent->id, query, sizeof(ent->id)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < le16_to_cpu(rsc_hdr->cnt)) {
|
||||
memcpy(eh, ent, sizeof(*ent));
|
||||
memcpy(rh, rsc_hdr, sizeof(*rh));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* cmd_db_read_addr() - Query command db for resource id address.
|
||||
*
|
||||
* @id: resource id to query for address
|
||||
*
|
||||
* Return: resource address on success, 0 on error
|
||||
*
|
||||
* This is used to retrieve resource address based on resource
|
||||
* id.
|
||||
*/
|
||||
u32 cmd_db_read_addr(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
|
||||
return ret < 0 ? 0 : le32_to_cpu(ent.addr);
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_addr);
|
||||
|
||||
/**
|
||||
* cmd_db_read_aux_data() - Query command db for aux data.
|
||||
*
|
||||
* @id: Resource to retrieve AUX Data on.
|
||||
* @data: Data buffer to copy returned aux data to. Returns size on NULL
|
||||
* @len: Caller provides size of data buffer passed in.
|
||||
*
|
||||
* Return: size of data on success, errno otherwise
|
||||
*/
|
||||
int cmd_db_read_aux_data(const char *id, u8 *data, size_t len)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
u16 ent_len;
|
||||
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ent_len = le16_to_cpu(ent.len);
|
||||
if (len < ent_len)
|
||||
return -EINVAL;
|
||||
|
||||
len = min_t(u16, ent_len, len);
|
||||
memcpy(data, rsc_offset(&rsc_hdr, &ent), len);
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_aux_data);
|
||||
|
||||
/**
|
||||
* cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB.
|
||||
*
|
||||
* @id: Resource to retrieve AUX Data.
|
||||
*
|
||||
* Return: size on success, 0 on error
|
||||
*/
|
||||
size_t cmd_db_read_aux_data_len(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
|
||||
return ret < 0 ? 0 : le16_to_cpu(ent.len);
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_aux_data_len);
|
||||
|
||||
/**
|
||||
* cmd_db_read_slave_id - Get the slave ID for a given resource address
|
||||
*
|
||||
* @id: Resource id to query the DB for version
|
||||
*
|
||||
* Return: cmd_db_hw_type enum on success, CMD_DB_HW_INVALID on error
|
||||
*/
|
||||
enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
|
||||
{
|
||||
int ret;
|
||||
struct entry_header ent;
|
||||
struct rsc_hdr rsc_hdr;
|
||||
u32 addr;
|
||||
|
||||
ret = cmd_db_get_header(id, &ent, &rsc_hdr);
|
||||
if (ret < 0)
|
||||
return CMD_DB_HW_INVALID;
|
||||
|
||||
addr = le32_to_cpu(ent.addr);
|
||||
return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_slave_id);
|
||||
|
||||
static int cmd_db_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct reserved_mem *rmem;
|
||||
int ret = 0;
|
||||
|
||||
rmem = of_reserved_mem_lookup(pdev->dev.of_node);
|
||||
if (!rmem) {
|
||||
dev_err(&pdev->dev, "failed to acquire memory region\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
|
||||
if (IS_ERR_OR_NULL(cmd_db_header)) {
|
||||
ret = PTR_ERR(cmd_db_header);
|
||||
cmd_db_header = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!cmd_db_magic_matches(cmd_db_header)) {
|
||||
dev_err(&pdev->dev, "Invalid Command DB Magic\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cmd_db_match_table[] = {
|
||||
{ .compatible = "qcom,cmd-db" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver cmd_db_dev_driver = {
|
||||
.probe = cmd_db_dev_probe,
|
||||
.driver = {
|
||||
.name = "cmd-db",
|
||||
.of_match_table = cmd_db_match_table,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init cmd_db_device_init(void)
|
||||
{
|
||||
return platform_driver_register(&cmd_db_dev_driver);
|
||||
}
|
||||
arch_initcall(cmd_db_device_init);
|
748
drivers/soc/qcom/qcom-geni-se.c
Normal file
748
drivers/soc/qcom/qcom-geni-se.c
Normal file
@ -0,0 +1,748 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/qcom-geni-se.h>
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
*
|
||||
* Generic Interface (GENI) Serial Engine (SE) Wrapper driver is introduced
|
||||
* to manage GENI firmware based Qualcomm Universal Peripheral (QUP) Wrapper
|
||||
* controller. QUP Wrapper is designed to support various serial bus protocols
|
||||
* like UART, SPI, I2C, I3C, etc.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Hardware description
|
||||
*
|
||||
* GENI based QUP is a highly-flexible and programmable module for supporting
|
||||
* a wide range of serial interfaces like UART, SPI, I2C, I3C, etc. A single
|
||||
* QUP module can provide upto 8 serial interfaces, using its internal
|
||||
* serial engines. The actual configuration is determined by the target
|
||||
* platform configuration. The protocol supported by each interface is
|
||||
* determined by the firmware loaded to the serial engine. Each SE consists
|
||||
* of a DMA Engine and GENI sub modules which enable serial engines to
|
||||
* support FIFO and DMA modes of operation.
|
||||
*
|
||||
*
|
||||
* +-----------------------------------------+
|
||||
* |QUP Wrapper |
|
||||
* | +----------------------------+ |
|
||||
* --QUP & SE Clocks--> | Serial Engine N | +-IO------>
|
||||
* | | ... | | Interface
|
||||
* <---Clock Perf.----+ +----+-----------------------+ | |
|
||||
* State Interface | | Serial Engine 1 | | |
|
||||
* | | | | |
|
||||
* | | | | |
|
||||
* <--------AHB-------> | | | |
|
||||
* | | +----+ |
|
||||
* | | | |
|
||||
* | | | |
|
||||
* <------SE IRQ------+ +----------------------------+ |
|
||||
* | |
|
||||
* +-----------------------------------------+
|
||||
*
|
||||
* Figure 1: GENI based QUP Wrapper
|
||||
*
|
||||
* The GENI submodules include primary and secondary sequencers which are
|
||||
* used to drive TX & RX operations. On serial interfaces that operate using
|
||||
* master-slave model, primary sequencer drives both TX & RX operations. On
|
||||
* serial interfaces that operate using peer-to-peer model, primary sequencer
|
||||
* drives TX operation and secondary sequencer drives RX operation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Software description
|
||||
*
|
||||
* GENI SE Wrapper driver is structured into 2 parts:
|
||||
*
|
||||
* geni_wrapper represents QUP Wrapper controller. This part of the driver
|
||||
* manages QUP Wrapper information such as hardware version, clock
|
||||
* performance table that is common to all the internal serial engines.
|
||||
*
|
||||
* geni_se represents serial engine. This part of the driver manages serial
|
||||
* engine information such as clocks, containing QUP Wrapper, etc. This part
|
||||
* of driver also supports operations (eg. initialize the concerned serial
|
||||
* engine, select between FIFO and DMA mode of operation etc.) that are
|
||||
* common to all the serial engines and are independent of serial interfaces.
|
||||
*/
|
||||
|
||||
#define MAX_CLK_PERF_LEVEL 32
|
||||
#define NUM_AHB_CLKS 2
|
||||
|
||||
/**
|
||||
* @struct geni_wrapper - Data structure to represent the QUP Wrapper Core
|
||||
* @dev: Device pointer of the QUP wrapper core
|
||||
* @base: Base address of this instance of QUP wrapper core
|
||||
* @ahb_clks: Handle to the primary & secondary AHB clocks
|
||||
*/
|
||||
struct geni_wrapper {
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
struct clk_bulk_data ahb_clks[NUM_AHB_CLKS];
|
||||
};
|
||||
|
||||
#define QUP_HW_VER_REG 0x4
|
||||
|
||||
/* Common SE registers */
|
||||
#define GENI_INIT_CFG_REVISION 0x0
|
||||
#define GENI_S_INIT_CFG_REVISION 0x4
|
||||
#define GENI_OUTPUT_CTRL 0x24
|
||||
#define GENI_CGC_CTRL 0x28
|
||||
#define GENI_CLK_CTRL_RO 0x60
|
||||
#define GENI_IF_DISABLE_RO 0x64
|
||||
#define GENI_FW_S_REVISION_RO 0x6c
|
||||
#define SE_GENI_BYTE_GRAN 0x254
|
||||
#define SE_GENI_TX_PACKING_CFG0 0x260
|
||||
#define SE_GENI_TX_PACKING_CFG1 0x264
|
||||
#define SE_GENI_RX_PACKING_CFG0 0x284
|
||||
#define SE_GENI_RX_PACKING_CFG1 0x288
|
||||
#define SE_GENI_M_GP_LENGTH 0x910
|
||||
#define SE_GENI_S_GP_LENGTH 0x914
|
||||
#define SE_DMA_TX_PTR_L 0xc30
|
||||
#define SE_DMA_TX_PTR_H 0xc34
|
||||
#define SE_DMA_TX_ATTR 0xc38
|
||||
#define SE_DMA_TX_LEN 0xc3c
|
||||
#define SE_DMA_TX_IRQ_EN 0xc48
|
||||
#define SE_DMA_TX_IRQ_EN_SET 0xc4c
|
||||
#define SE_DMA_TX_IRQ_EN_CLR 0xc50
|
||||
#define SE_DMA_TX_LEN_IN 0xc54
|
||||
#define SE_DMA_TX_MAX_BURST 0xc5c
|
||||
#define SE_DMA_RX_PTR_L 0xd30
|
||||
#define SE_DMA_RX_PTR_H 0xd34
|
||||
#define SE_DMA_RX_ATTR 0xd38
|
||||
#define SE_DMA_RX_LEN 0xd3c
|
||||
#define SE_DMA_RX_IRQ_EN 0xd48
|
||||
#define SE_DMA_RX_IRQ_EN_SET 0xd4c
|
||||
#define SE_DMA_RX_IRQ_EN_CLR 0xd50
|
||||
#define SE_DMA_RX_LEN_IN 0xd54
|
||||
#define SE_DMA_RX_MAX_BURST 0xd5c
|
||||
#define SE_DMA_RX_FLUSH 0xd60
|
||||
#define SE_GSI_EVENT_EN 0xe18
|
||||
#define SE_IRQ_EN 0xe1c
|
||||
#define SE_DMA_GENERAL_CFG 0xe30
|
||||
|
||||
/* GENI_OUTPUT_CTRL fields */
|
||||
#define DEFAULT_IO_OUTPUT_CTRL_MSK GENMASK(6, 0)
|
||||
|
||||
/* GENI_CGC_CTRL fields */
|
||||
#define CFG_AHB_CLK_CGC_ON BIT(0)
|
||||
#define CFG_AHB_WR_ACLK_CGC_ON BIT(1)
|
||||
#define DATA_AHB_CLK_CGC_ON BIT(2)
|
||||
#define SCLK_CGC_ON BIT(3)
|
||||
#define TX_CLK_CGC_ON BIT(4)
|
||||
#define RX_CLK_CGC_ON BIT(5)
|
||||
#define EXT_CLK_CGC_ON BIT(6)
|
||||
#define PROG_RAM_HCLK_OFF BIT(8)
|
||||
#define PROG_RAM_SCLK_OFF BIT(9)
|
||||
#define DEFAULT_CGC_EN GENMASK(6, 0)
|
||||
|
||||
/* SE_GSI_EVENT_EN fields */
|
||||
#define DMA_RX_EVENT_EN BIT(0)
|
||||
#define DMA_TX_EVENT_EN BIT(1)
|
||||
#define GENI_M_EVENT_EN BIT(2)
|
||||
#define GENI_S_EVENT_EN BIT(3)
|
||||
|
||||
/* SE_IRQ_EN fields */
|
||||
#define DMA_RX_IRQ_EN BIT(0)
|
||||
#define DMA_TX_IRQ_EN BIT(1)
|
||||
#define GENI_M_IRQ_EN BIT(2)
|
||||
#define GENI_S_IRQ_EN BIT(3)
|
||||
|
||||
/* SE_DMA_GENERAL_CFG */
|
||||
#define DMA_RX_CLK_CGC_ON BIT(0)
|
||||
#define DMA_TX_CLK_CGC_ON BIT(1)
|
||||
#define DMA_AHB_SLV_CFG_ON BIT(2)
|
||||
#define AHB_SEC_SLV_CLK_CGC_ON BIT(3)
|
||||
#define DUMMY_RX_NON_BUFFERABLE BIT(4)
|
||||
#define RX_DMA_ZERO_PADDING_EN BIT(5)
|
||||
#define RX_DMA_IRQ_DELAY_MSK GENMASK(8, 6)
|
||||
#define RX_DMA_IRQ_DELAY_SHFT 6
|
||||
|
||||
/**
|
||||
* geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version
|
||||
* @se: Pointer to the corresponding serial engine.
|
||||
*
|
||||
* Return: Hardware Version of the wrapper.
|
||||
*/
|
||||
u32 geni_se_get_qup_hw_version(struct geni_se *se)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
return readl_relaxed(wrapper->base + QUP_HW_VER_REG);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_get_qup_hw_version);
|
||||
|
||||
static void geni_se_io_set_mode(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(base + SE_IRQ_EN);
|
||||
val |= GENI_M_IRQ_EN | GENI_S_IRQ_EN;
|
||||
val |= DMA_TX_IRQ_EN | DMA_RX_IRQ_EN;
|
||||
writel_relaxed(val, base + SE_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(base + SE_GENI_DMA_MODE_EN);
|
||||
val &= ~GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, base + SE_GENI_DMA_MODE_EN);
|
||||
|
||||
writel_relaxed(0, base + SE_GSI_EVENT_EN);
|
||||
}
|
||||
|
||||
static void geni_se_io_init(void __iomem *base)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(base + GENI_CGC_CTRL);
|
||||
val |= DEFAULT_CGC_EN;
|
||||
writel_relaxed(val, base + GENI_CGC_CTRL);
|
||||
|
||||
val = readl_relaxed(base + SE_DMA_GENERAL_CFG);
|
||||
val |= AHB_SEC_SLV_CLK_CGC_ON | DMA_AHB_SLV_CFG_ON;
|
||||
val |= DMA_TX_CLK_CGC_ON | DMA_RX_CLK_CGC_ON;
|
||||
writel_relaxed(val, base + SE_DMA_GENERAL_CFG);
|
||||
|
||||
writel_relaxed(DEFAULT_IO_OUTPUT_CTRL_MSK, base + GENI_OUTPUT_CTRL);
|
||||
writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_init() - Initialize the GENI serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @rx_wm: Receive watermark, in units of FIFO words.
|
||||
* @rx_rfr_wm: Ready-for-receive watermark, in units of FIFO words.
|
||||
*
|
||||
* This function is used to initialize the GENI serial engine, configure
|
||||
* receive watermark and ready-for-receive watermarks.
|
||||
*/
|
||||
void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
geni_se_io_init(se->base);
|
||||
geni_se_io_set_mode(se->base);
|
||||
|
||||
writel_relaxed(rx_wm, se->base + SE_GENI_RX_WATERMARK_REG);
|
||||
writel_relaxed(rx_rfr, se->base + SE_GENI_RX_RFR_WATERMARK_REG);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
val |= M_COMMON_GENI_M_IRQ_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
val |= S_COMMON_GENI_S_IRQ_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_init);
|
||||
|
||||
static void geni_se_select_fifo_mode(struct geni_se *se)
|
||||
{
|
||||
u32 proto = geni_se_read_proto(se);
|
||||
u32 val;
|
||||
|
||||
writel_relaxed(0, se->base + SE_GSI_EVENT_EN);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN);
|
||||
if (proto != GENI_SE_UART) {
|
||||
val |= M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN;
|
||||
val |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN;
|
||||
}
|
||||
writel_relaxed(val, se->base + SE_GENI_M_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_S_IRQ_EN);
|
||||
if (proto != GENI_SE_UART)
|
||||
val |= S_CMD_DONE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val &= ~GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
static void geni_se_select_dma_mode(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
writel_relaxed(0, se->base + SE_GSI_EVENT_EN);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR);
|
||||
writel_relaxed(0xffffffff, se->base + SE_IRQ_EN);
|
||||
|
||||
val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN);
|
||||
val |= GENI_DMA_MODE_EN;
|
||||
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_select_mode() - Select the serial engine transfer mode
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @mode: Transfer mode to be selected.
|
||||
*/
|
||||
void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
|
||||
{
|
||||
WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA);
|
||||
|
||||
switch (mode) {
|
||||
case GENI_SE_FIFO:
|
||||
geni_se_select_fifo_mode(se);
|
||||
break;
|
||||
case GENI_SE_DMA:
|
||||
geni_se_select_dma_mode(se);
|
||||
break;
|
||||
case GENI_SE_INVALID:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_select_mode);
|
||||
|
||||
/**
|
||||
* DOC: Overview
|
||||
*
|
||||
* GENI FIFO packing is highly configurable. TX/RX packing/unpacking consist
|
||||
* of up to 4 operations, each operation represented by 4 configuration vectors
|
||||
* of 10 bits programmed in GENI_TX_PACKING_CFG0 and GENI_TX_PACKING_CFG1 for
|
||||
* TX FIFO and in GENI_RX_PACKING_CFG0 and GENI_RX_PACKING_CFG1 for RX FIFO.
|
||||
* Refer to below examples for detailed bit-field description.
|
||||
*
|
||||
* Example 1: word_size = 7, packing_mode = 4 x 8, msb_to_lsb = 1
|
||||
*
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | | vec_0 | vec_1 | vec_2 | vec_3 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | start | 0x6 | 0xe | 0x16 | 0x1e |
|
||||
* | direction | 1 | 1 | 1 | 1 |
|
||||
* | length | 6 | 6 | 6 | 6 |
|
||||
* | stop | 0 | 0 | 0 | 1 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
*
|
||||
* Example 2: word_size = 15, packing_mode = 2 x 16, msb_to_lsb = 0
|
||||
*
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | | vec_0 | vec_1 | vec_2 | vec_3 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | start | 0x0 | 0x8 | 0x10 | 0x18 |
|
||||
* | direction | 0 | 0 | 0 | 0 |
|
||||
* | length | 7 | 6 | 7 | 6 |
|
||||
* | stop | 0 | 0 | 0 | 1 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
*
|
||||
* Example 3: word_size = 23, packing_mode = 1 x 32, msb_to_lsb = 1
|
||||
*
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | | vec_0 | vec_1 | vec_2 | vec_3 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
* | start | 0x16 | 0xe | 0x6 | 0x0 |
|
||||
* | direction | 1 | 1 | 1 | 1 |
|
||||
* | length | 7 | 7 | 6 | 0 |
|
||||
* | stop | 0 | 0 | 1 | 0 |
|
||||
* +-----------+-------+-------+-------+-------+
|
||||
*
|
||||
*/
|
||||
|
||||
#define NUM_PACKING_VECTORS 4
|
||||
#define PACKING_START_SHIFT 5
|
||||
#define PACKING_DIR_SHIFT 4
|
||||
#define PACKING_LEN_SHIFT 1
|
||||
#define PACKING_STOP_BIT BIT(0)
|
||||
#define PACKING_VECTOR_SHIFT 10
|
||||
/**
|
||||
* geni_se_config_packing() - Packing configuration of the serial engine
|
||||
* @se: Pointer to the concerned serial engine
|
||||
* @bpw: Bits of data per transfer word.
|
||||
* @pack_words: Number of words per fifo element.
|
||||
* @msb_to_lsb: Transfer from MSB to LSB or vice-versa.
|
||||
* @tx_cfg: Flag to configure the TX Packing.
|
||||
* @rx_cfg: Flag to configure the RX Packing.
|
||||
*
|
||||
* This function is used to configure the packing rules for the current
|
||||
* transfer.
|
||||
*/
|
||||
void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words,
|
||||
bool msb_to_lsb, bool tx_cfg, bool rx_cfg)
|
||||
{
|
||||
u32 cfg0, cfg1, cfg[NUM_PACKING_VECTORS] = {0};
|
||||
int len;
|
||||
int temp_bpw = bpw;
|
||||
int idx_start = msb_to_lsb ? bpw - 1 : 0;
|
||||
int idx = idx_start;
|
||||
int idx_delta = msb_to_lsb ? -BITS_PER_BYTE : BITS_PER_BYTE;
|
||||
int ceil_bpw = ALIGN(bpw, BITS_PER_BYTE);
|
||||
int iter = (ceil_bpw * pack_words) / BITS_PER_BYTE;
|
||||
int i;
|
||||
|
||||
if (iter <= 0 || iter > NUM_PACKING_VECTORS)
|
||||
return;
|
||||
|
||||
for (i = 0; i < iter; i++) {
|
||||
len = min_t(int, temp_bpw, BITS_PER_BYTE) - 1;
|
||||
cfg[i] = idx << PACKING_START_SHIFT;
|
||||
cfg[i] |= msb_to_lsb << PACKING_DIR_SHIFT;
|
||||
cfg[i] |= len << PACKING_LEN_SHIFT;
|
||||
|
||||
if (temp_bpw <= BITS_PER_BYTE) {
|
||||
idx = ((i + 1) * BITS_PER_BYTE) + idx_start;
|
||||
temp_bpw = bpw;
|
||||
} else {
|
||||
idx = idx + idx_delta;
|
||||
temp_bpw = temp_bpw - BITS_PER_BYTE;
|
||||
}
|
||||
}
|
||||
cfg[iter - 1] |= PACKING_STOP_BIT;
|
||||
cfg0 = cfg[0] | (cfg[1] << PACKING_VECTOR_SHIFT);
|
||||
cfg1 = cfg[2] | (cfg[3] << PACKING_VECTOR_SHIFT);
|
||||
|
||||
if (tx_cfg) {
|
||||
writel_relaxed(cfg0, se->base + SE_GENI_TX_PACKING_CFG0);
|
||||
writel_relaxed(cfg1, se->base + SE_GENI_TX_PACKING_CFG1);
|
||||
}
|
||||
if (rx_cfg) {
|
||||
writel_relaxed(cfg0, se->base + SE_GENI_RX_PACKING_CFG0);
|
||||
writel_relaxed(cfg1, se->base + SE_GENI_RX_PACKING_CFG1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Number of protocol words in each FIFO entry
|
||||
* 0 - 4x8, four words in each entry, max word size of 8 bits
|
||||
* 1 - 2x16, two words in each entry, max word size of 16 bits
|
||||
* 2 - 1x32, one word in each entry, max word size of 32 bits
|
||||
* 3 - undefined
|
||||
*/
|
||||
if (pack_words || bpw == 32)
|
||||
writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_config_packing);
|
||||
|
||||
static void geni_se_clks_off(struct geni_se *se)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
clk_disable_unprepare(se->clk);
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_resources_off() - Turn off resources associated with the serial
|
||||
* engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure/error.
|
||||
*/
|
||||
int geni_se_resources_off(struct geni_se *se)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = pinctrl_pm_select_sleep_state(se->dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
geni_se_clks_off(se);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_resources_off);
|
||||
|
||||
static int geni_se_clks_on(struct geni_se *se)
|
||||
{
|
||||
int ret;
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(se->clk);
|
||||
if (ret)
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(wrapper->ahb_clks),
|
||||
wrapper->ahb_clks);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_resources_on() - Turn on resources associated with the serial
|
||||
* engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure/error.
|
||||
*/
|
||||
int geni_se_resources_on(struct geni_se *se)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = geni_se_clks_on(se);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pinctrl_pm_select_default_state(se->dev);
|
||||
if (ret)
|
||||
geni_se_clks_off(se);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_resources_on);
|
||||
|
||||
/**
|
||||
* geni_se_clk_tbl_get() - Get the clock table to program DFS
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @tbl: Table in which the output is returned.
|
||||
*
|
||||
* This function is called by the protocol drivers to determine the different
|
||||
* clock frequencies supported by serial engine core clock. The protocol
|
||||
* drivers use the output to determine the clock frequency index to be
|
||||
* programmed into DFS.
|
||||
*
|
||||
* Return: number of valid performance levels in the table on success,
|
||||
* standard Linux error codes on failure.
|
||||
*/
|
||||
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
|
||||
{
|
||||
unsigned long freq = 0;
|
||||
int i;
|
||||
|
||||
if (se->clk_perf_tbl) {
|
||||
*tbl = se->clk_perf_tbl;
|
||||
return se->num_clk_levels;
|
||||
}
|
||||
|
||||
se->clk_perf_tbl = devm_kcalloc(se->dev, MAX_CLK_PERF_LEVEL,
|
||||
sizeof(*se->clk_perf_tbl),
|
||||
GFP_KERNEL);
|
||||
if (!se->clk_perf_tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
|
||||
freq = clk_round_rate(se->clk, freq + 1);
|
||||
if (!freq || freq == se->clk_perf_tbl[i - 1])
|
||||
break;
|
||||
se->clk_perf_tbl[i] = freq;
|
||||
}
|
||||
se->num_clk_levels = i;
|
||||
*tbl = se->clk_perf_tbl;
|
||||
return se->num_clk_levels;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_clk_tbl_get);
|
||||
|
||||
/**
|
||||
* geni_se_clk_freq_match() - Get the matching or closest SE clock frequency
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @req_freq: Requested clock frequency.
|
||||
* @index: Index of the resultant frequency in the table.
|
||||
* @res_freq: Resultant frequency which matches or is closer to the
|
||||
* requested frequency.
|
||||
* @exact: Flag to indicate exact multiple requirement of the requested
|
||||
* frequency.
|
||||
*
|
||||
* This function is called by the protocol drivers to determine the matching
|
||||
* or exact multiple of the requested frequency, as provided by the serial
|
||||
* engine clock in order to meet the performance requirements. If there is
|
||||
* no matching or exact multiple of the requested frequency found, then it
|
||||
* selects the closest floor frequency, if exact flag is not set.
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure.
|
||||
*/
|
||||
int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
|
||||
unsigned int *index, unsigned long *res_freq,
|
||||
bool exact)
|
||||
{
|
||||
unsigned long *tbl;
|
||||
int num_clk_levels;
|
||||
int i;
|
||||
|
||||
num_clk_levels = geni_se_clk_tbl_get(se, &tbl);
|
||||
if (num_clk_levels < 0)
|
||||
return num_clk_levels;
|
||||
|
||||
if (num_clk_levels == 0)
|
||||
return -EINVAL;
|
||||
|
||||
*res_freq = 0;
|
||||
for (i = 0; i < num_clk_levels; i++) {
|
||||
if (!(tbl[i] % req_freq)) {
|
||||
*index = i;
|
||||
*res_freq = tbl[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(*res_freq) || ((tbl[i] > *res_freq) &&
|
||||
(tbl[i] < req_freq))) {
|
||||
*index = i;
|
||||
*res_freq = tbl[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (exact)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_clk_freq_match);
|
||||
|
||||
#define GENI_SE_DMA_DONE_EN BIT(0)
|
||||
#define GENI_SE_DMA_EOT_EN BIT(1)
|
||||
#define GENI_SE_DMA_AHB_ERR_EN BIT(2)
|
||||
#define GENI_SE_DMA_EOT_BUF BIT(0)
|
||||
/**
|
||||
* geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @buf: Pointer to the TX buffer.
|
||||
* @len: Length of the TX buffer.
|
||||
* @iova: Pointer to store the mapped DMA address.
|
||||
*
|
||||
* This function is used to prepare the buffers for DMA TX.
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure.
|
||||
*/
|
||||
int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
u32 val;
|
||||
|
||||
*iova = dma_map_single(wrapper->dev, buf, len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(wrapper->dev, *iova))
|
||||
return -EIO;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_TX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_TX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_TX_PTR_H);
|
||||
writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_TX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_dma_prep);
|
||||
|
||||
/**
|
||||
* geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @buf: Pointer to the RX buffer.
|
||||
* @len: Length of the RX buffer.
|
||||
* @iova: Pointer to store the mapped DMA address.
|
||||
*
|
||||
* This function is used to prepare the buffers for DMA RX.
|
||||
*
|
||||
* Return: 0 on success, standard Linux error codes on failure.
|
||||
*/
|
||||
int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
u32 val;
|
||||
|
||||
*iova = dma_map_single(wrapper->dev, buf, len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(wrapper->dev, *iova))
|
||||
return -EIO;
|
||||
|
||||
val = GENI_SE_DMA_DONE_EN;
|
||||
val |= GENI_SE_DMA_EOT_EN;
|
||||
val |= GENI_SE_DMA_AHB_ERR_EN;
|
||||
writel_relaxed(val, se->base + SE_DMA_RX_IRQ_EN_SET);
|
||||
writel_relaxed(lower_32_bits(*iova), se->base + SE_DMA_RX_PTR_L);
|
||||
writel_relaxed(upper_32_bits(*iova), se->base + SE_DMA_RX_PTR_H);
|
||||
/* RX does not have EOT buffer type bit. So just reset RX_ATTR */
|
||||
writel_relaxed(0, se->base + SE_DMA_RX_ATTR);
|
||||
writel_relaxed(len, se->base + SE_DMA_RX_LEN);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_dma_prep);
|
||||
|
||||
/**
|
||||
* geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @iova: DMA address of the TX buffer.
|
||||
* @len: Length of the TX buffer.
|
||||
*
|
||||
* This function is used to unprepare the DMA buffers after DMA TX.
|
||||
*/
|
||||
void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
if (iova && !dma_mapping_error(wrapper->dev, iova))
|
||||
dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_tx_dma_unprep);
|
||||
|
||||
/**
|
||||
* geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @iova: DMA address of the RX buffer.
|
||||
* @len: Length of the RX buffer.
|
||||
*
|
||||
* This function is used to unprepare the DMA buffers after DMA RX.
|
||||
*/
|
||||
void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
|
||||
{
|
||||
struct geni_wrapper *wrapper = se->wrapper;
|
||||
|
||||
if (iova && !dma_mapping_error(wrapper->dev, iova))
|
||||
dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE);
|
||||
}
|
||||
EXPORT_SYMBOL(geni_se_rx_dma_unprep);
|
||||
|
||||
static int geni_se_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct geni_wrapper *wrapper;
|
||||
int ret;
|
||||
|
||||
wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL);
|
||||
if (!wrapper)
|
||||
return -ENOMEM;
|
||||
|
||||
wrapper->dev = dev;
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
wrapper->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(wrapper->base))
|
||||
return PTR_ERR(wrapper->base);
|
||||
|
||||
wrapper->ahb_clks[0].id = "m-ahb";
|
||||
wrapper->ahb_clks[1].id = "s-ahb";
|
||||
ret = devm_clk_bulk_get(dev, NUM_AHB_CLKS, wrapper->ahb_clks);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err getting AHB clks %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, wrapper);
|
||||
dev_dbg(dev, "GENI SE Driver probed\n");
|
||||
return devm_of_platform_populate(dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id geni_se_dt_match[] = {
|
||||
{ .compatible = "qcom,geni-se-qup", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, geni_se_dt_match);
|
||||
|
||||
static struct platform_driver geni_se_driver = {
|
||||
.driver = {
|
||||
.name = "geni_se_qup",
|
||||
.of_match_table = geni_se_dt_match,
|
||||
},
|
||||
.probe = geni_se_probe,
|
||||
};
|
||||
module_platform_driver(geni_se_driver);
|
||||
|
||||
MODULE_DESCRIPTION("GENI Serial Engine Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -639,10 +639,11 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size,
|
||||
if (ops)
|
||||
qmi->ops = *ops;
|
||||
|
||||
/* Make room for the header */
|
||||
recv_buf_size += sizeof(struct qmi_header);
|
||||
/* Must also be sufficient to hold a control packet */
|
||||
if (recv_buf_size < sizeof(struct qrtr_ctrl_pkt))
|
||||
recv_buf_size = sizeof(struct qrtr_ctrl_pkt);
|
||||
else
|
||||
recv_buf_size += sizeof(struct qmi_header);
|
||||
|
||||
qmi->recv_buf_size = recv_buf_size;
|
||||
qmi->recv_buf = kzalloc(recv_buf_size, GFP_KERNEL);
|
||||
|
@ -226,6 +226,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
|
||||
{ .compatible = "qcom,rpm-msm8916" },
|
||||
{ .compatible = "qcom,rpm-msm8974" },
|
||||
{ .compatible = "qcom,rpm-msm8996" },
|
||||
{ .compatible = "qcom,rpm-msm8998" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match);
|
||||
|
@ -280,7 +280,7 @@ struct qcom_smem {
|
||||
struct smem_region regions[0];
|
||||
};
|
||||
|
||||
static struct smem_private_entry *
|
||||
static void *
|
||||
phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
|
||||
{
|
||||
void *p = phdr;
|
||||
@ -288,15 +288,18 @@ phdr_to_last_uncached_entry(struct smem_partition_header *phdr)
|
||||
return p + le32_to_cpu(phdr->offset_free_uncached);
|
||||
}
|
||||
|
||||
static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr,
|
||||
static struct smem_private_entry *
|
||||
phdr_to_first_cached_entry(struct smem_partition_header *phdr,
|
||||
size_t cacheline)
|
||||
{
|
||||
void *p = phdr;
|
||||
struct smem_private_entry *e;
|
||||
|
||||
return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*phdr), cacheline);
|
||||
return p + le32_to_cpu(phdr->size) - ALIGN(sizeof(*e), cacheline);
|
||||
}
|
||||
|
||||
static void *phdr_to_last_cached_entry(struct smem_partition_header *phdr)
|
||||
static void *
|
||||
phdr_to_last_cached_entry(struct smem_partition_header *phdr)
|
||||
{
|
||||
void *p = phdr;
|
||||
|
||||
@ -361,14 +364,14 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
||||
end = phdr_to_last_uncached_entry(phdr);
|
||||
cached = phdr_to_last_cached_entry(phdr);
|
||||
|
||||
while (hdr < end) {
|
||||
if (hdr->canary != SMEM_PRIVATE_CANARY) {
|
||||
dev_err(smem->dev,
|
||||
"Found invalid canary in hosts %d:%d partition\n",
|
||||
phdr->host0, phdr->host1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (smem->global_partition) {
|
||||
dev_err(smem->dev, "Already found the global partition\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
while (hdr < end) {
|
||||
if (hdr->canary != SMEM_PRIVATE_CANARY)
|
||||
goto bad_canary;
|
||||
if (le16_to_cpu(hdr->item) == item)
|
||||
return -EEXIST;
|
||||
|
||||
@ -377,7 +380,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
||||
|
||||
/* Check that we don't grow into the cached region */
|
||||
alloc_size = sizeof(*hdr) + ALIGN(size, 8);
|
||||
if ((void *)hdr + alloc_size >= cached) {
|
||||
if ((void *)hdr + alloc_size > cached) {
|
||||
dev_err(smem->dev, "Out of memory\n");
|
||||
return -ENOSPC;
|
||||
}
|
||||
@ -397,6 +400,11 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
|
||||
le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
|
||||
|
||||
return 0;
|
||||
bad_canary:
|
||||
dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
|
||||
le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int qcom_smem_alloc_global(struct qcom_smem *smem,
|
||||
@ -560,8 +568,8 @@ static void *qcom_smem_get_private(struct qcom_smem *smem,
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
invalid_canary:
|
||||
dev_err(smem->dev, "Found invalid canary in hosts %d:%d partition\n",
|
||||
phdr->host0, phdr->host1);
|
||||
dev_err(smem->dev, "Found invalid canary in hosts %hu:%hu partition\n",
|
||||
le16_to_cpu(phdr->host0), le16_to_cpu(phdr->host1));
|
||||
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
@ -647,6 +655,33 @@ int qcom_smem_get_free_space(unsigned host)
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smem_get_free_space);
|
||||
|
||||
/**
|
||||
* qcom_smem_virt_to_phys() - return the physical address associated
|
||||
* with an smem item pointer (previously returned by qcom_smem_get()
|
||||
* @p: the virtual address to convert
|
||||
*
|
||||
* Returns 0 if the pointer provided is not within any smem region.
|
||||
*/
|
||||
phys_addr_t qcom_smem_virt_to_phys(void *p)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < __smem->num_regions; i++) {
|
||||
struct smem_region *region = &__smem->regions[i];
|
||||
|
||||
if (p < region->virt_base)
|
||||
continue;
|
||||
if (p < region->virt_base + region->size) {
|
||||
u64 offset = p - region->virt_base;
|
||||
|
||||
return (phys_addr_t)region->aux_base + offset;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_smem_virt_to_phys);
|
||||
|
||||
static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
|
||||
{
|
||||
struct smem_header *header;
|
||||
@ -695,9 +730,10 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
|
||||
static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
||||
{
|
||||
struct smem_partition_header *header;
|
||||
struct smem_ptable_entry *entry = NULL;
|
||||
struct smem_ptable_entry *entry;
|
||||
struct smem_ptable *ptable;
|
||||
u32 host0, host1, size;
|
||||
bool found = false;
|
||||
int i;
|
||||
|
||||
ptable = qcom_smem_get_ptable(smem);
|
||||
@ -709,11 +745,13 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
||||
host0 = le16_to_cpu(entry->host0);
|
||||
host1 = le16_to_cpu(entry->host1);
|
||||
|
||||
if (host0 == SMEM_GLOBAL_HOST && host0 == host1)
|
||||
if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
if (!found) {
|
||||
dev_err(smem->dev, "Missing entry for global partition\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -723,11 +761,6 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (smem->global_partition) {
|
||||
dev_err(smem->dev, "Already found the global partition\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
|
||||
host0 = le16_to_cpu(header->host0);
|
||||
host1 = le16_to_cpu(header->host1);
|
||||
|
425
include/linux/qcom-geni-se.h
Normal file
425
include/linux/qcom-geni-se.h
Normal file
@ -0,0 +1,425 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_QCOM_GENI_SE
|
||||
#define _LINUX_QCOM_GENI_SE
|
||||
|
||||
/* Transfer mode supported by GENI Serial Engines */
|
||||
enum geni_se_xfer_mode {
|
||||
GENI_SE_INVALID,
|
||||
GENI_SE_FIFO,
|
||||
GENI_SE_DMA,
|
||||
};
|
||||
|
||||
/* Protocols supported by GENI Serial Engines */
|
||||
enum geni_se_protocol_type {
|
||||
GENI_SE_NONE,
|
||||
GENI_SE_SPI,
|
||||
GENI_SE_UART,
|
||||
GENI_SE_I2C,
|
||||
GENI_SE_I3C,
|
||||
};
|
||||
|
||||
struct geni_wrapper;
|
||||
struct clk;
|
||||
|
||||
/**
|
||||
* struct geni_se - GENI Serial Engine
|
||||
* @base: Base Address of the Serial Engine's register block
|
||||
* @dev: Pointer to the Serial Engine device
|
||||
* @wrapper: Pointer to the parent QUP Wrapper core
|
||||
* @clk: Handle to the core serial engine clock
|
||||
* @num_clk_levels: Number of valid clock levels in clk_perf_tbl
|
||||
* @clk_perf_tbl: Table of clock frequency input to serial engine clock
|
||||
*/
|
||||
struct geni_se {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
struct geni_wrapper *wrapper;
|
||||
struct clk *clk;
|
||||
unsigned int num_clk_levels;
|
||||
unsigned long *clk_perf_tbl;
|
||||
};
|
||||
|
||||
/* Common SE registers */
|
||||
#define GENI_FORCE_DEFAULT_REG 0x20
|
||||
#define SE_GENI_STATUS 0x40
|
||||
#define GENI_SER_M_CLK_CFG 0x48
|
||||
#define GENI_SER_S_CLK_CFG 0x4c
|
||||
#define GENI_FW_REVISION_RO 0x68
|
||||
#define SE_GENI_CLK_SEL 0x7c
|
||||
#define SE_GENI_DMA_MODE_EN 0x258
|
||||
#define SE_GENI_M_CMD0 0x600
|
||||
#define SE_GENI_M_CMD_CTRL_REG 0x604
|
||||
#define SE_GENI_M_IRQ_STATUS 0x610
|
||||
#define SE_GENI_M_IRQ_EN 0x614
|
||||
#define SE_GENI_M_IRQ_CLEAR 0x618
|
||||
#define SE_GENI_S_CMD0 0x630
|
||||
#define SE_GENI_S_CMD_CTRL_REG 0x634
|
||||
#define SE_GENI_S_IRQ_STATUS 0x640
|
||||
#define SE_GENI_S_IRQ_EN 0x644
|
||||
#define SE_GENI_S_IRQ_CLEAR 0x648
|
||||
#define SE_GENI_TX_FIFOn 0x700
|
||||
#define SE_GENI_RX_FIFOn 0x780
|
||||
#define SE_GENI_TX_FIFO_STATUS 0x800
|
||||
#define SE_GENI_RX_FIFO_STATUS 0x804
|
||||
#define SE_GENI_TX_WATERMARK_REG 0x80c
|
||||
#define SE_GENI_RX_WATERMARK_REG 0x810
|
||||
#define SE_GENI_RX_RFR_WATERMARK_REG 0x814
|
||||
#define SE_GENI_IOS 0x908
|
||||
#define SE_DMA_TX_IRQ_STAT 0xc40
|
||||
#define SE_DMA_TX_IRQ_CLR 0xc44
|
||||
#define SE_DMA_TX_FSM_RST 0xc58
|
||||
#define SE_DMA_RX_IRQ_STAT 0xd40
|
||||
#define SE_DMA_RX_IRQ_CLR 0xd44
|
||||
#define SE_DMA_RX_FSM_RST 0xd58
|
||||
#define SE_HW_PARAM_0 0xe24
|
||||
#define SE_HW_PARAM_1 0xe28
|
||||
|
||||
/* GENI_FORCE_DEFAULT_REG fields */
|
||||
#define FORCE_DEFAULT BIT(0)
|
||||
|
||||
/* GENI_STATUS fields */
|
||||
#define M_GENI_CMD_ACTIVE BIT(0)
|
||||
#define S_GENI_CMD_ACTIVE BIT(12)
|
||||
|
||||
/* GENI_SER_M_CLK_CFG/GENI_SER_S_CLK_CFG */
|
||||
#define SER_CLK_EN BIT(0)
|
||||
#define CLK_DIV_MSK GENMASK(15, 4)
|
||||
#define CLK_DIV_SHFT 4
|
||||
|
||||
/* GENI_FW_REVISION_RO fields */
|
||||
#define FW_REV_PROTOCOL_MSK GENMASK(15, 8)
|
||||
#define FW_REV_PROTOCOL_SHFT 8
|
||||
|
||||
/* GENI_CLK_SEL fields */
|
||||
#define CLK_SEL_MSK GENMASK(2, 0)
|
||||
|
||||
/* SE_GENI_DMA_MODE_EN */
|
||||
#define GENI_DMA_MODE_EN BIT(0)
|
||||
|
||||
/* GENI_M_CMD0 fields */
|
||||
#define M_OPCODE_MSK GENMASK(31, 27)
|
||||
#define M_OPCODE_SHFT 27
|
||||
#define M_PARAMS_MSK GENMASK(26, 0)
|
||||
|
||||
/* GENI_M_CMD_CTRL_REG */
|
||||
#define M_GENI_CMD_CANCEL BIT(2)
|
||||
#define M_GENI_CMD_ABORT BIT(1)
|
||||
#define M_GENI_DISABLE BIT(0)
|
||||
|
||||
/* GENI_S_CMD0 fields */
|
||||
#define S_OPCODE_MSK GENMASK(31, 27)
|
||||
#define S_OPCODE_SHFT 27
|
||||
#define S_PARAMS_MSK GENMASK(26, 0)
|
||||
|
||||
/* GENI_S_CMD_CTRL_REG */
|
||||
#define S_GENI_CMD_CANCEL BIT(2)
|
||||
#define S_GENI_CMD_ABORT BIT(1)
|
||||
#define S_GENI_DISABLE BIT(0)
|
||||
|
||||
/* GENI_M_IRQ_EN fields */
|
||||
#define M_CMD_DONE_EN BIT(0)
|
||||
#define M_CMD_OVERRUN_EN BIT(1)
|
||||
#define M_ILLEGAL_CMD_EN BIT(2)
|
||||
#define M_CMD_FAILURE_EN BIT(3)
|
||||
#define M_CMD_CANCEL_EN BIT(4)
|
||||
#define M_CMD_ABORT_EN BIT(5)
|
||||
#define M_TIMESTAMP_EN BIT(6)
|
||||
#define M_RX_IRQ_EN BIT(7)
|
||||
#define M_GP_SYNC_IRQ_0_EN BIT(8)
|
||||
#define M_GP_IRQ_0_EN BIT(9)
|
||||
#define M_GP_IRQ_1_EN BIT(10)
|
||||
#define M_GP_IRQ_2_EN BIT(11)
|
||||
#define M_GP_IRQ_3_EN BIT(12)
|
||||
#define M_GP_IRQ_4_EN BIT(13)
|
||||
#define M_GP_IRQ_5_EN BIT(14)
|
||||
#define M_IO_DATA_DEASSERT_EN BIT(22)
|
||||
#define M_IO_DATA_ASSERT_EN BIT(23)
|
||||
#define M_RX_FIFO_RD_ERR_EN BIT(24)
|
||||
#define M_RX_FIFO_WR_ERR_EN BIT(25)
|
||||
#define M_RX_FIFO_WATERMARK_EN BIT(26)
|
||||
#define M_RX_FIFO_LAST_EN BIT(27)
|
||||
#define M_TX_FIFO_RD_ERR_EN BIT(28)
|
||||
#define M_TX_FIFO_WR_ERR_EN BIT(29)
|
||||
#define M_TX_FIFO_WATERMARK_EN BIT(30)
|
||||
#define M_SEC_IRQ_EN BIT(31)
|
||||
#define M_COMMON_GENI_M_IRQ_EN (GENMASK(6, 1) | \
|
||||
M_IO_DATA_DEASSERT_EN | \
|
||||
M_IO_DATA_ASSERT_EN | M_RX_FIFO_RD_ERR_EN | \
|
||||
M_RX_FIFO_WR_ERR_EN | M_TX_FIFO_RD_ERR_EN | \
|
||||
M_TX_FIFO_WR_ERR_EN)
|
||||
|
||||
/* GENI_S_IRQ_EN fields */
|
||||
#define S_CMD_DONE_EN BIT(0)
|
||||
#define S_CMD_OVERRUN_EN BIT(1)
|
||||
#define S_ILLEGAL_CMD_EN BIT(2)
|
||||
#define S_CMD_FAILURE_EN BIT(3)
|
||||
#define S_CMD_CANCEL_EN BIT(4)
|
||||
#define S_CMD_ABORT_EN BIT(5)
|
||||
#define S_GP_SYNC_IRQ_0_EN BIT(8)
|
||||
#define S_GP_IRQ_0_EN BIT(9)
|
||||
#define S_GP_IRQ_1_EN BIT(10)
|
||||
#define S_GP_IRQ_2_EN BIT(11)
|
||||
#define S_GP_IRQ_3_EN BIT(12)
|
||||
#define S_GP_IRQ_4_EN BIT(13)
|
||||
#define S_GP_IRQ_5_EN BIT(14)
|
||||
#define S_IO_DATA_DEASSERT_EN BIT(22)
|
||||
#define S_IO_DATA_ASSERT_EN BIT(23)
|
||||
#define S_RX_FIFO_RD_ERR_EN BIT(24)
|
||||
#define S_RX_FIFO_WR_ERR_EN BIT(25)
|
||||
#define S_RX_FIFO_WATERMARK_EN BIT(26)
|
||||
#define S_RX_FIFO_LAST_EN BIT(27)
|
||||
#define S_COMMON_GENI_S_IRQ_EN (GENMASK(5, 1) | GENMASK(13, 9) | \
|
||||
S_RX_FIFO_RD_ERR_EN | S_RX_FIFO_WR_ERR_EN)
|
||||
|
||||
/* GENI_/TX/RX/RX_RFR/_WATERMARK_REG fields */
|
||||
#define WATERMARK_MSK GENMASK(5, 0)
|
||||
|
||||
/* GENI_TX_FIFO_STATUS fields */
|
||||
#define TX_FIFO_WC GENMASK(27, 0)
|
||||
|
||||
/* GENI_RX_FIFO_STATUS fields */
|
||||
#define RX_LAST BIT(31)
|
||||
#define RX_LAST_BYTE_VALID_MSK GENMASK(30, 28)
|
||||
#define RX_LAST_BYTE_VALID_SHFT 28
|
||||
#define RX_FIFO_WC_MSK GENMASK(24, 0)
|
||||
|
||||
/* SE_GENI_IOS fields */
|
||||
#define IO2_DATA_IN BIT(1)
|
||||
#define RX_DATA_IN BIT(0)
|
||||
|
||||
/* SE_DMA_TX_IRQ_STAT Register fields */
|
||||
#define TX_DMA_DONE BIT(0)
|
||||
#define TX_EOT BIT(1)
|
||||
#define TX_SBE BIT(2)
|
||||
#define TX_RESET_DONE BIT(3)
|
||||
|
||||
/* SE_DMA_RX_IRQ_STAT Register fields */
|
||||
#define RX_DMA_DONE BIT(0)
|
||||
#define RX_EOT BIT(1)
|
||||
#define RX_SBE BIT(2)
|
||||
#define RX_RESET_DONE BIT(3)
|
||||
#define RX_FLUSH_DONE BIT(4)
|
||||
#define RX_GENI_GP_IRQ GENMASK(10, 5)
|
||||
#define RX_GENI_CANCEL_IRQ BIT(11)
|
||||
#define RX_GENI_GP_IRQ_EXT GENMASK(13, 12)
|
||||
|
||||
/* SE_HW_PARAM_0 fields */
|
||||
#define TX_FIFO_WIDTH_MSK GENMASK(29, 24)
|
||||
#define TX_FIFO_WIDTH_SHFT 24
|
||||
#define TX_FIFO_DEPTH_MSK GENMASK(21, 16)
|
||||
#define TX_FIFO_DEPTH_SHFT 16
|
||||
|
||||
/* SE_HW_PARAM_1 fields */
|
||||
#define RX_FIFO_WIDTH_MSK GENMASK(29, 24)
|
||||
#define RX_FIFO_WIDTH_SHFT 24
|
||||
#define RX_FIFO_DEPTH_MSK GENMASK(21, 16)
|
||||
#define RX_FIFO_DEPTH_SHFT 16
|
||||
|
||||
#define HW_VER_MAJOR_MASK GENMASK(31, 28)
|
||||
#define HW_VER_MAJOR_SHFT 28
|
||||
#define HW_VER_MINOR_MASK GENMASK(27, 16)
|
||||
#define HW_VER_MINOR_SHFT 16
|
||||
#define HW_VER_STEP_MASK GENMASK(15, 0)
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_GENI_SE)
|
||||
|
||||
u32 geni_se_get_qup_hw_version(struct geni_se *se);
|
||||
|
||||
#define geni_se_get_wrapper_version(se, major, minor, step) do { \
|
||||
u32 ver; \
|
||||
\
|
||||
ver = geni_se_get_qup_hw_version(se); \
|
||||
major = (ver & HW_VER_MAJOR_MASK) >> HW_VER_MAJOR_SHFT; \
|
||||
minor = (ver & HW_VER_MINOR_MASK) >> HW_VER_MINOR_SHFT; \
|
||||
step = version & HW_VER_STEP_MASK; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* geni_se_read_proto() - Read the protocol configured for a serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* Return: Protocol value as configured in the serial engine.
|
||||
*/
|
||||
static inline u32 geni_se_read_proto(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(se->base + GENI_FW_REVISION_RO);
|
||||
|
||||
return (val & FW_REV_PROTOCOL_MSK) >> FW_REV_PROTOCOL_SHFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_setup_m_cmd() - Setup the primary sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @cmd: Command/Operation to setup in the primary sequencer.
|
||||
* @params: Parameter for the sequencer command.
|
||||
*
|
||||
* This function is used to configure the primary sequencer with the
|
||||
* command and its associated parameters.
|
||||
*/
|
||||
static inline void geni_se_setup_m_cmd(struct geni_se *se, u32 cmd, u32 params)
|
||||
{
|
||||
u32 m_cmd;
|
||||
|
||||
m_cmd = (cmd << M_OPCODE_SHFT) | (params & M_PARAMS_MSK);
|
||||
writel_relaxed(m_cmd, se->base + SE_GENI_M_CMD0);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_setup_s_cmd() - Setup the secondary sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
* @cmd: Command/Operation to setup in the secondary sequencer.
|
||||
* @params: Parameter for the sequencer command.
|
||||
*
|
||||
* This function is used to configure the secondary sequencer with the
|
||||
* command and its associated parameters.
|
||||
*/
|
||||
static inline void geni_se_setup_s_cmd(struct geni_se *se, u32 cmd, u32 params)
|
||||
{
|
||||
u32 s_cmd;
|
||||
|
||||
s_cmd = readl_relaxed(se->base + SE_GENI_S_CMD0);
|
||||
s_cmd &= ~(S_OPCODE_MSK | S_PARAMS_MSK);
|
||||
s_cmd |= (cmd << S_OPCODE_SHFT);
|
||||
s_cmd |= (params & S_PARAMS_MSK);
|
||||
writel_relaxed(s_cmd, se->base + SE_GENI_S_CMD0);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_cancel_m_cmd() - Cancel the command configured in the primary
|
||||
* sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to cancel the currently configured command in the
|
||||
* primary sequencer.
|
||||
*/
|
||||
static inline void geni_se_cancel_m_cmd(struct geni_se *se)
|
||||
{
|
||||
writel_relaxed(M_GENI_CMD_CANCEL, se->base + SE_GENI_M_CMD_CTRL_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_cancel_s_cmd() - Cancel the command configured in the secondary
|
||||
* sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to cancel the currently configured command in the
|
||||
* secondary sequencer.
|
||||
*/
|
||||
static inline void geni_se_cancel_s_cmd(struct geni_se *se)
|
||||
{
|
||||
writel_relaxed(S_GENI_CMD_CANCEL, se->base + SE_GENI_S_CMD_CTRL_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_abort_m_cmd() - Abort the command configured in the primary sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to force abort the currently configured command in the
|
||||
* primary sequencer.
|
||||
*/
|
||||
static inline void geni_se_abort_m_cmd(struct geni_se *se)
|
||||
{
|
||||
writel_relaxed(M_GENI_CMD_ABORT, se->base + SE_GENI_M_CMD_CTRL_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_abort_s_cmd() - Abort the command configured in the secondary
|
||||
* sequencer
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to force abort the currently configured command in the
|
||||
* secondary sequencer.
|
||||
*/
|
||||
static inline void geni_se_abort_s_cmd(struct geni_se *se)
|
||||
{
|
||||
writel_relaxed(S_GENI_CMD_ABORT, se->base + SE_GENI_S_CMD_CTRL_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_get_tx_fifo_depth() - Get the TX fifo depth of the serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to get the depth i.e. number of elements in the
|
||||
* TX fifo of the serial engine.
|
||||
*
|
||||
* Return: TX fifo depth in units of FIFO words.
|
||||
*/
|
||||
static inline u32 geni_se_get_tx_fifo_depth(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(se->base + SE_HW_PARAM_0);
|
||||
|
||||
return (val & TX_FIFO_DEPTH_MSK) >> TX_FIFO_DEPTH_SHFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_get_tx_fifo_width() - Get the TX fifo width of the serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to get the width i.e. word size per element in the
|
||||
* TX fifo of the serial engine.
|
||||
*
|
||||
* Return: TX fifo width in bits
|
||||
*/
|
||||
static inline u32 geni_se_get_tx_fifo_width(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(se->base + SE_HW_PARAM_0);
|
||||
|
||||
return (val & TX_FIFO_WIDTH_MSK) >> TX_FIFO_WIDTH_SHFT;
|
||||
}
|
||||
|
||||
/**
|
||||
* geni_se_get_rx_fifo_depth() - Get the RX fifo depth of the serial engine
|
||||
* @se: Pointer to the concerned serial engine.
|
||||
*
|
||||
* This function is used to get the depth i.e. number of elements in the
|
||||
* RX fifo of the serial engine.
|
||||
*
|
||||
* Return: RX fifo depth in units of FIFO words
|
||||
*/
|
||||
static inline u32 geni_se_get_rx_fifo_depth(struct geni_se *se)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = readl_relaxed(se->base + SE_HW_PARAM_1);
|
||||
|
||||
return (val & RX_FIFO_DEPTH_MSK) >> RX_FIFO_DEPTH_SHFT;
|
||||
}
|
||||
|
||||
void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr);
|
||||
|
||||
void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode);
|
||||
|
||||
void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words,
|
||||
bool msb_to_lsb, bool tx_cfg, bool rx_cfg);
|
||||
|
||||
int geni_se_resources_off(struct geni_se *se);
|
||||
|
||||
int geni_se_resources_on(struct geni_se *se);
|
||||
|
||||
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl);
|
||||
|
||||
int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
|
||||
unsigned int *index, unsigned long *res_freq,
|
||||
bool exact);
|
||||
|
||||
int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova);
|
||||
|
||||
int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len,
|
||||
dma_addr_t *iova);
|
||||
|
||||
void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);
|
||||
|
||||
void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len);
|
||||
#endif
|
||||
#endif
|
@ -9,4 +9,6 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size);
|
||||
|
||||
int qcom_smem_get_free_space(unsigned host);
|
||||
|
||||
phys_addr_t qcom_smem_virt_to_phys(void *p);
|
||||
|
||||
#endif
|
||||
|
45
include/soc/qcom/cmd-db.h
Normal file
45
include/soc/qcom/cmd-db.h
Normal file
@ -0,0 +1,45 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
|
||||
|
||||
#ifndef __QCOM_COMMAND_DB_H__
|
||||
#define __QCOM_COMMAND_DB_H__
|
||||
|
||||
|
||||
enum cmd_db_hw_type {
|
||||
CMD_DB_HW_INVALID = 0,
|
||||
CMD_DB_HW_MIN = 3,
|
||||
CMD_DB_HW_ARC = CMD_DB_HW_MIN,
|
||||
CMD_DB_HW_VRM = 4,
|
||||
CMD_DB_HW_BCM = 5,
|
||||
CMD_DB_HW_MAX = CMD_DB_HW_BCM,
|
||||
CMD_DB_HW_ALL = 0xff,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_QCOM_COMMAND_DB)
|
||||
u32 cmd_db_read_addr(const char *resource_id);
|
||||
|
||||
int cmd_db_read_aux_data(const char *resource_id, u8 *data, size_t len);
|
||||
|
||||
size_t cmd_db_read_aux_data_len(const char *resource_id);
|
||||
|
||||
enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id);
|
||||
|
||||
int cmd_db_ready(void);
|
||||
#else
|
||||
static inline u32 cmd_db_read_addr(const char *resource_id)
|
||||
{ return 0; }
|
||||
|
||||
static inline int cmd_db_read_aux_data(const char *resource_id, u8 *data,
|
||||
size_t len)
|
||||
{ return -ENODEV; }
|
||||
|
||||
static inline size_t cmd_db_read_aux_data_len(const char *resource_id)
|
||||
{ return -ENODEV; }
|
||||
|
||||
static inline enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id)
|
||||
{ return -ENODEV; }
|
||||
|
||||
static inline int cmd_db_ready(void)
|
||||
{ return -ENODEV; }
|
||||
#endif /* CONFIG_QCOM_COMMAND_DB */
|
||||
#endif /* __QCOM_COMMAND_DB_H__ */
|
Loading…
Reference in New Issue
Block a user