diff --git a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts index 35c17f7c11ea..7bbcb280b05f 100644 --- a/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts +++ b/arch/arm64/boot/dts/qcom/milos-fairphone-fp6.dts @@ -27,6 +27,34 @@ serial1 = &uart11; }; + /* + * The sensor I2C bus sits on TLMM eGPIO pads that have no AP QUP + * function; on the stock OS it is driven by an island QUP of the + * Snapdragon Sensor Core (ADSP). From the AP the pads are only + * usable as software GPIOs, so bit-bang the bus. + * Devices on the bus: QMC6308 magnetometer @ 0x2c, SPL07 + * barometer @ 0x76, STK3BCx ALS/proximity @ 0x48. + */ + i2c-sensors { + compatible = "i2c-gpio"; + sda-gpios = <&tlmm 153 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + scl-gpios = <&tlmm 154 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>; + i2c-gpio,delay-us = <2>; + pinctrl-0 = <&sensor_i2c_default>; + pinctrl-names = "default"; + #address-cells = <1>; + #size-cells = <0>; + + magnetometer@2c { + compatible = "qstcorp,qmc6308"; + reg = <0x2c>; + vdd-supply = <&vreg_l10b>; + mount-matrix = "0", "-1", "0", + "1", "0", "0", + "0", "0", "1"; + }; + }; + gpio-keys { compatible = "gpio-keys"; @@ -1189,6 +1217,14 @@ bias-disable; }; + sensor_i2c_default: sensor-i2c-default-state { + /* SDA, SCL; external pull-ups to vreg_l10b */ + pins = "gpio153", "gpio154"; + function = "gpio"; + drive-strength = <2>; + bias-disable; + }; + ts_active: ts-irq-active-state { pins = "gpio19"; function = "gpio"; diff --git a/arch/arm64/boot/dts/qcom/milos.dtsi b/arch/arm64/boot/dts/qcom/milos.dtsi index 0f95a9976de7..288e0e658629 100644 --- a/arch/arm64/boot/dts/qcom/milos.dtsi +++ b/arch/arm64/boot/dts/qcom/milos.dtsi @@ -548,14 +548,6 @@ no-map; }; - adsp_rpc_heap_mem: adsp-rpc-heap { - compatible = "shared-dma-pool"; - alloc-ranges = <0x0 0x0 0x0 0xffffffff>; - reusable; - alignment = <0x0 0x400000>; - size = <0x0 0xc00000>; - }; - pvm_fw_mem: pvm-fw-region@824a0000 { reg = <0x0 0x824a0000 0x0 0x100000>; no-map; @@ -1406,9 +1398,6 @@ qcom,glink-channels = "fastrpcglink-apps-dsp"; label = "adsp"; qcom,non-secure-domain; - memory-region = <&adsp_rpc_heap_mem>; - qcom,vmids = ; #address-cells = <1>; #size-cells = <0>; @@ -1433,8 +1422,6 @@ reg = <5>; iommus = <&apps_smmu 0x1005 0x0>, <&apps_smmu 0x1065 0x0>; - /* AUDIO_STATICPD bank, per downstream volcano-dsp.dtsi */ - pd-type = <2>; dma-coherent; }; diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig index fb313e591e85..7cd4d751e1d2 100644 --- a/drivers/iio/magnetometer/Kconfig +++ b/drivers/iio/magnetometer/Kconfig @@ -198,6 +198,17 @@ config INFINEON_TLV493D To compile this driver as a module, choose M here: the module will be called tlv493d. +config QMC6308 + tristate "QST QMC6308 3-Axis Magnetic Sensor" + depends on I2C + select REGMAP_I2C + help + Say Y here to add support for the QST QMC6308 3-Axis + Magnetic Sensor. + + To compile this driver as a module, choose M here: the + module will be called qmc6308. + config SENSORS_HMC5843 tristate select IIO_BUFFER diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile index 5bd227f8c120..59ea5cf17287 100644 --- a/drivers/iio/magnetometer/Makefile +++ b/drivers/iio/magnetometer/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_IIO_ST_MAGN_SPI_3AXIS) += st_magn_spi.o obj-$(CONFIG_INFINEON_TLV493D) += tlv493d.o +obj-$(CONFIG_QMC6308) += qmc6308.o + obj-$(CONFIG_SENSORS_HMC5843) += hmc5843_core.o obj-$(CONFIG_SENSORS_HMC5843_I2C) += hmc5843_i2c.o obj-$(CONFIG_SENSORS_HMC5843_SPI) += hmc5843_spi.o diff --git a/drivers/iio/magnetometer/qmc6308.c b/drivers/iio/magnetometer/qmc6308.c new file mode 100644 index 000000000000..ceb4b98402bb --- /dev/null +++ b/drivers/iio/magnetometer/qmc6308.c @@ -0,0 +1,590 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Support for QST QMC6308 3-Axis Magnetic Sensor on I2C bus. + * + * Copyright (C) 2026 Jorijn van der Graaf + * + * Datasheet available at + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define QMC6308_REG_ID 0x00 +#define QMC6308_REG_X_LSB 0x01 +#define QMC6308_REG_STATUS 0x09 +#define QMC6308_REG_CTRL1 0x0A +#define QMC6308_REG_CTRL2 0x0B +#define QMC6308_REG_CTRL3 0x0D +#define QMC6308_REG_CTRL4 0x29 + +#define QMC6308_CHIP_ID 0x80 + +/* Control register 1 */ +#define QMC6308_MODE_MASK GENMASK(1, 0) +#define QMC6308_ODR_MASK GENMASK(3, 2) +#define QMC6308_OSR1_MASK GENMASK(5, 4) +#define QMC6308_OSR2_MASK GENMASK(7, 6) + +#define QMC6308_MODE_SUSPEND 0x00 +#define QMC6308_MODE_NORMAL 0x01 + +#define QMC6308_ODR_10HZ 0x00 +#define QMC6308_ODR_50HZ 0x01 +#define QMC6308_ODR_100HZ 0x02 +#define QMC6308_ODR_200HZ 0x03 + +#define QMC6308_OSR1_8 0x00 +#define QMC6308_OSR1_4 0x01 +#define QMC6308_OSR1_2 0x02 +#define QMC6308_OSR1_1 0x03 + +/* Control register 2 */ +#define QMC6308_SET_RESET_MASK GENMASK(1, 0) +#define QMC6308_RNG_MASK GENMASK(3, 2) +#define QMC6308_SELF_TEST BIT(6) +#define QMC6308_SOFT_RST BIT(7) + +#define QMC6308_SET_RESET_ON 0x00 + +#define QMC6308_RNG_30G 0x00 +#define QMC6308_RNG_12G 0x01 +#define QMC6308_RNG_8G 0x02 +#define QMC6308_RNG_2G 0x03 + +/* Status register */ +#define QMC6308_STATUS_DRDY BIT(0) +#define QMC6308_STATUS_OVFL BIT(1) + +/* + * Power-on completion time (datasheet Table 7), also used as a + * conservative bound after soft reset, for which the datasheet + * gives no figure. + */ +#define QMC6308_POR_US 250 + +#define QMC6308_AUTOSUSPEND_DELAY_MS 500 + +struct qmc6308_data { + struct regmap *regmap; + /* + * Protect data->range/odr/osr. + * Protect poll and read during measurement (reading the status + * register clears DRDY). + */ + struct mutex mutex; + struct iio_mount_matrix orientation; + u8 range; + u8 odr; + u8 osr; +}; + +enum qmc6308_axis { + QMC6308_AXIS_X, + QMC6308_AXIS_Y, + QMC6308_AXIS_Z, +}; + +static const int qmc6308_odr_avail[] = { + [QMC6308_ODR_10HZ] = 10, + [QMC6308_ODR_50HZ] = 50, + [QMC6308_ODR_100HZ] = 100, + [QMC6308_ODR_200HZ] = 200, +}; + +static const int qmc6308_osr1_avail[] = { + [QMC6308_OSR1_8] = 8, + [QMC6308_OSR1_4] = 4, + [QMC6308_OSR1_2] = 2, + [QMC6308_OSR1_1] = 1, +}; + +/* + * Sensitivity is 1000/2500/3750/15000 LSB/Gauss for the + * +-30/12/8/2 Gauss ranges respectively. + */ +static const int qmc6308_scales[][2] = { + [QMC6308_RNG_30G] = { 0, 1000000 }, + [QMC6308_RNG_12G] = { 0, 400000 }, + [QMC6308_RNG_8G] = { 0, 266667 }, + [QMC6308_RNG_2G] = { 0, 66667 }, +}; + +static int qmc6308_set_mode(struct qmc6308_data *data, unsigned int mode) +{ + return regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_MODE_MASK, + FIELD_PREP(QMC6308_MODE_MASK, mode)); +} + +static int qmc6308_take_measurement(struct iio_dev *indio_dev, int index, + int *val) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + struct regmap *map = data->regmap; + struct device *dev = regmap_get_device(map); + unsigned int status; + __le16 buf[3]; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) { + /* EACCES means a read raced runtime PM disable on suspend */ + if (ret != -EACCES) + dev_err(dev, "Failed to power on (%d)\n", ret); + return ret; + } + + scoped_guard(mutex, &data->mutex) { + /* 50ms headroom over the slowest ODR (10Hz) */ + ret = regmap_read_poll_timeout(map, QMC6308_REG_STATUS, + status, + (status & QMC6308_STATUS_DRDY), + 2 * USEC_PER_MSEC, + 150 * USEC_PER_MSEC); + if (ret) + goto out_rpm_put; + + ret = regmap_bulk_read(map, QMC6308_REG_X_LSB, buf, + sizeof(buf)); + if (ret) + goto out_rpm_put; + + if (status & QMC6308_STATUS_OVFL) + ret = -ERANGE; + } + +out_rpm_put: + pm_runtime_put_autosuspend(dev); + if (ret) + return ret; + + *val = (s16)le16_to_cpu(buf[index]); + + return 0; +} + +static int qmc6308_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = qmc6308_take_measurement(indio_dev, chan->address, val); + if (ret) + return ret; + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: { + guard(mutex)(&data->mutex); + + *val = qmc6308_scales[data->range][0]; + *val2 = qmc6308_scales[data->range][1]; + + return IIO_VAL_INT_PLUS_NANO; + } + case IIO_CHAN_INFO_SAMP_FREQ: { + guard(mutex)(&data->mutex); + + *val = qmc6308_odr_avail[data->odr]; + + return IIO_VAL_INT; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + guard(mutex)(&data->mutex); + + *val = qmc6308_osr1_avail[data->osr]; + + return IIO_VAL_INT; + } + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int val, int val2, long mask) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + unsigned int i; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: { + if (val != 0) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(qmc6308_scales); i++) { + if (val2 == qmc6308_scales[i][1]) + break; + } + if (i == ARRAY_SIZE(qmc6308_scales)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL2, + QMC6308_RNG_MASK, + FIELD_PREP(QMC6308_RNG_MASK, i)); + if (ret) + return ret; + + data->range = i; + + /* + * The data registers still hold (and DRDY still + * advertises) a sample converted at the previous range; + * discard it so that the next read returns data matching + * the new scale. + */ + return regmap_read(data->regmap, QMC6308_REG_STATUS, + &status); + } + case IIO_CHAN_INFO_SAMP_FREQ: { + for (i = 0; i < ARRAY_SIZE(qmc6308_odr_avail); i++) { + if (val == qmc6308_odr_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_odr_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_ODR_MASK, + FIELD_PREP(QMC6308_ODR_MASK, i)); + if (ret) + return ret; + + data->odr = i; + + return 0; + } + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: { + for (i = 0; i < ARRAY_SIZE(qmc6308_osr1_avail); i++) { + if (val == qmc6308_osr1_avail[i]) + break; + } + if (i == ARRAY_SIZE(qmc6308_osr1_avail)) + return -EINVAL; + + guard(mutex)(&data->mutex); + + ret = regmap_update_bits(data->regmap, QMC6308_REG_CTRL1, + QMC6308_OSR1_MASK, + FIELD_PREP(QMC6308_OSR1_MASK, i)); + if (ret) + return ret; + + data->osr = i; + + return 0; + } + default: + return -EINVAL; + } +} + +static int qmc6308_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = qmc6308_odr_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_odr_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = qmc6308_osr1_avail; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(qmc6308_osr1_avail); + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SCALE: + *vals = (const int *)qmc6308_scales; + *type = IIO_VAL_INT_PLUS_NANO; + *length = ARRAY_SIZE(qmc6308_scales) * 2; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int qmc6308_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return IIO_VAL_INT_PLUS_NANO; + default: + return IIO_VAL_INT; + } +} + +static const struct iio_mount_matrix * +qmc6308_get_mount_matrix(const struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct qmc6308_data *data = iio_priv(indio_dev); + + return &data->orientation; +} + +static const struct iio_chan_spec_ext_info qmc6308_ext_info[] = { + IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, qmc6308_get_mount_matrix), + { } +}; + +static const struct iio_info qmc6308_info = { + .read_raw = qmc6308_read_raw, + .write_raw = qmc6308_write_raw, + .read_avail = qmc6308_read_avail, + .write_raw_get_fmt = qmc6308_write_raw_get_fmt, +}; + +static int qmc6308_init(struct qmc6308_data *data) +{ + struct regmap *map = data->regmap; + unsigned int reg; + int ret; + + ret = regmap_read(map, QMC6308_REG_ID, ®); + if (ret) + return ret; + + /* Allow unknown IDs so that fallback compatibles work */ + if (reg != QMC6308_CHIP_ID) + dev_warn(regmap_get_device(map), + "Unknown chip id: 0x%02x, continuing\n", reg); + + /* The SOFT_RST bit is not auto-cleared and must be written back 0 */ + ret = regmap_write(map, QMC6308_REG_CTRL2, QMC6308_SOFT_RST); + if (ret) + return ret; + + fsleep(QMC6308_POR_US); + + data->range = QMC6308_RNG_30G; + + ret = regmap_write(map, QMC6308_REG_CTRL2, + FIELD_PREP(QMC6308_SET_RESET_MASK, + QMC6308_SET_RESET_ON) | + FIELD_PREP(QMC6308_RNG_MASK, data->range)); + if (ret) + return ret; + + data->odr = QMC6308_ODR_50HZ; + data->osr = QMC6308_OSR1_8; + + return regmap_write(map, QMC6308_REG_CTRL1, + FIELD_PREP(QMC6308_MODE_MASK, + QMC6308_MODE_NORMAL) | + FIELD_PREP(QMC6308_ODR_MASK, data->odr) | + FIELD_PREP(QMC6308_OSR1_MASK, data->osr)); +} + +static void qmc6308_power_down_action(void *priv) +{ + struct qmc6308_data *data = priv; + + if (!pm_runtime_status_suspended(regmap_get_device(data->regmap))) + qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static bool qmc6308_volatile_reg(struct device *dev, unsigned int reg) +{ + return reg >= QMC6308_REG_X_LSB && reg <= QMC6308_REG_STATUS; +} + +static bool qmc6308_writable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case QMC6308_REG_CTRL1: + case QMC6308_REG_CTRL2: + case QMC6308_REG_CTRL3: + case QMC6308_REG_CTRL4: + return true; + default: + return false; + } +} + +static const struct regmap_config qmc6308_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = QMC6308_REG_CTRL4, + .cache_type = REGCACHE_MAPLE, + .volatile_reg = qmc6308_volatile_reg, + .writeable_reg = qmc6308_writable_reg, +}; + +#define QMC6308_CHANNEL(_axis) \ + { \ + .type = IIO_MAGN, \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ + .address = QMC6308_AXIS_##_axis, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .info_mask_shared_by_type_available = \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \ + .ext_info = qmc6308_ext_info, \ + } + +static const struct iio_chan_spec qmc6308_channels[] = { + QMC6308_CHANNEL(X), + QMC6308_CHANNEL(Y), + QMC6308_CHANNEL(Z), +}; + +static int qmc6308_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct qmc6308_data *data; + struct iio_dev *indio_dev; + struct regmap *map; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + + map = devm_regmap_init_i2c(client, &qmc6308_regmap_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), + "regmap initialization failed\n"); + + ret = devm_regulator_get_enable(dev, "vdd"); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable VDD regulator\n"); + + fsleep(QMC6308_POR_US); + + data = iio_priv(indio_dev); + data->regmap = map; + + ret = devm_mutex_init(dev, &data->mutex); + if (ret) + return ret; + + ret = iio_read_mount_matrix(dev, &data->orientation); + if (ret) + return dev_err_probe(dev, ret, + "Failed to read mount matrix\n"); + + indio_dev->name = "qmc6308"; + indio_dev->info = &qmc6308_info; + indio_dev->channels = qmc6308_channels; + indio_dev->num_channels = ARRAY_SIZE(qmc6308_channels); + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = qmc6308_init(data); + if (ret) + return dev_err_probe(dev, ret, "qmc6308 init failed\n"); + + pm_runtime_set_active(dev); + + ret = devm_add_action_or_reset(dev, qmc6308_power_down_action, data); + if (ret) + return ret; + + pm_runtime_get_noresume(dev); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_autosuspend_delay(dev, QMC6308_AUTOSUSPEND_DELAY_MS); + ret = devm_pm_runtime_enable(dev); + if (ret) + return ret; + + pm_runtime_put_autosuspend(dev); + + return devm_iio_device_register(dev, indio_dev); +} + +static int qmc6308_runtime_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + + return qmc6308_set_mode(data, QMC6308_MODE_SUSPEND); +} + +static int qmc6308_runtime_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + struct qmc6308_data *data = iio_priv(indio_dev); + unsigned int status; + int ret; + + ret = qmc6308_set_mode(data, QMC6308_MODE_NORMAL); + if (ret) + return ret; + + /* + * DRDY may still be set for a sample converted before the last + * suspend; clear it so the next read waits for fresh data. + */ + return regmap_read(data->regmap, QMC6308_REG_STATUS, &status); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(qmc6308_pm_ops, qmc6308_runtime_suspend, + qmc6308_runtime_resume, NULL); + +static const struct of_device_id qmc6308_match[] = { + { .compatible = "qstcorp,qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(of, qmc6308_match); + +static const struct i2c_device_id qmc6308_id[] = { + { .name = "qmc6308" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, qmc6308_id); + +static struct i2c_driver qmc6308_driver = { + .driver = { + .name = "qmc6308", + .of_match_table = qmc6308_match, + .pm = pm_ptr(&qmc6308_pm_ops), + }, + .id_table = qmc6308_id, + .probe = qmc6308_probe, +}; +module_i2c_driver(qmc6308_driver); + +MODULE_DESCRIPTION("QST QMC6308 3-Axis Magnetic Sensor driver"); +MODULE_AUTHOR("Jorijn van der Graaf "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index cb29a429af78..f3a49384586d 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -103,13 +103,6 @@ #define USER_PD (1) #define SENSORS_PD (2) -/* - * Downstream DT "pd-type" context-bank designations (volcano-dsp.dtsi). - * A static PD must be spawned on its designated context bank / SMMU - * stream or the DSP treats it as a generic signed PD. - */ -#define FASTRPC_DT_PD_TYPE_AUDIO_STATICPD 2 - #define miscdev_to_fdevice(d) container_of(d, struct fastrpc_device, miscdev) struct fastrpc_phy_page { @@ -262,8 +255,6 @@ struct fastrpc_session_ctx { int sid; bool used; bool valid; - /* downstream DT pd-type this context bank is dedicated to (0 = generic) */ - u32 pd_type; }; struct fastrpc_soc_data { @@ -323,11 +314,6 @@ struct fastrpc_user { struct kref refcount; }; -static struct fastrpc_session_ctx *fastrpc_session_alloc_pd_type( - struct fastrpc_user *fl, u32 pd_type); -static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx, - struct fastrpc_session_ctx *session); - /* Extract SMMU PA from consolidated IOVA */ static inline dma_addr_t fastrpc_ipa_to_dma_addr(struct fastrpc_channel_ctx *cctx, dma_addr_t iova) { @@ -1357,7 +1343,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, struct fastrpc_phy_page pages[1]; char *name; int err; - bool scm_done = false, heap_created = false; + bool scm_done = false; struct { int client_id; u32 namelen; @@ -1385,35 +1371,11 @@ static int fastrpc_init_create_static_process(struct fastrpc_user *fl, goto err; } - /* - * The audio static PD must live on its designated context bank so the - * DSP sees its memory on the audio SMMU stream; on a generic bank the - * aDSP enforces module signing in the PD (dlopen of unsigned dynamic - * modules fails demanding a testsig). Re-route before anything is - * allocated against the session. Falls back to the already-held - * generic session if no bank is tagged in DT. - */ - if (init.namelen >= strlen("audiopd") && - !memcmp(name, "audiopd", strlen("audiopd"))) { - struct fastrpc_session_ctx *audio_sess; - - audio_sess = fastrpc_session_alloc_pd_type(fl, - FASTRPC_DT_PD_TYPE_AUDIO_STATICPD); - if (audio_sess) { - fastrpc_session_free(fl->cctx, fl->sctx); - fl->sctx = audio_sess; - } - dev_info(&fl->cctx->rpdev->dev, - "audiopd: using session sid %d (%s)\n", fl->sctx->sid, - audio_sess ? "dedicated audio CB" : "no audio CB in DT"); - } - if (!fl->cctx->remote_heap) { err = fastrpc_remote_heap_alloc(fl, fl->sctx->dev, init.memlen, &fl->cctx->remote_heap); if (err) goto err_name; - heap_created = true; /* Map if we have any heap VMIDs associated with this ADSP Static Process. */ if (fl->cctx->vmcount) { @@ -1484,16 +1446,8 @@ err_invoke: &fl->cctx->remote_heap->dma_addr, fl->cctx->remote_heap->size, err); } err_map: - /* - * A heap reused from an earlier spawn is still SCM-assigned to the - * remote VMIDs; freeing it here would return protected pages to the - * allocator and a later touch crashes with a synchronous external - * abort. Keep it for the next spawn attempt. - */ - if (heap_created) { - fastrpc_buf_free(fl->cctx->remote_heap); - fl->cctx->remote_heap = NULL; - } + fastrpc_buf_free(fl->cctx->remote_heap); + fl->cctx->remote_heap = NULL; err_name: kfree(name); err: @@ -1628,9 +1582,7 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc( spin_lock_irqsave(&cctx->lock, flags); for (i = 0; i < cctx->sesscount; i++) { - /* dedicated static-PD context banks are assigned by pd_type only */ - if (!cctx->session[i].used && cctx->session[i].valid && - !cctx->session[i].pd_type) { + if (!cctx->session[i].used && cctx->session[i].valid) { cctx->session[i].used = true; session = &cctx->session[i]; /* any non-zero ID will work, session_idx + 1 is the simplest one */ @@ -1643,29 +1595,6 @@ static struct fastrpc_session_ctx *fastrpc_session_alloc( return session; } -static struct fastrpc_session_ctx *fastrpc_session_alloc_pd_type( - struct fastrpc_user *fl, u32 pd_type) -{ - struct fastrpc_channel_ctx *cctx = fl->cctx; - struct fastrpc_session_ctx *session = NULL; - unsigned long flags; - int i; - - spin_lock_irqsave(&cctx->lock, flags); - for (i = 0; i < cctx->sesscount; i++) { - if (!cctx->session[i].used && cctx->session[i].valid && - cctx->session[i].pd_type == pd_type) { - cctx->session[i].used = true; - session = &cctx->session[i]; - fl->client_id = i + 1; - break; - } - } - spin_unlock_irqrestore(&cctx->lock, flags); - - return session; -} - static void fastrpc_session_free(struct fastrpc_channel_ctx *cctx, struct fastrpc_session_ctx *session) { @@ -2322,9 +2251,6 @@ static int fastrpc_cb_probe(struct platform_device *pdev) if (of_property_read_u32(dev->of_node, "reg", &sess->sid)) dev_info(dev, "FastRPC Session ID not specified in DT\n"); - sess->pd_type = 0; - of_property_read_u32(dev->of_node, "pd-type", &sess->pd_type); - if (sessions > 0) { struct fastrpc_session_ctx *dup_sess; diff --git a/net/qrtr/af_qrtr.c b/net/qrtr/af_qrtr.c index aae337572be7..db823177e636 100644 --- a/net/qrtr/af_qrtr.c +++ b/net/qrtr/af_qrtr.c @@ -520,54 +520,6 @@ int qrtr_endpoint_post(struct qrtr_endpoint *ep, const void *data, size_t len) qrtr_node_assign(node, le32_to_cpu(pkt->server.node)); } - /* The DSPs are star-connected through this node: forward packets - * destined to another node onto that node's endpoint (e.g. the - * modem's voice stack talking to the ADSP's audio service). Only - * DATA and RESUME_TX transit; control packets keep going to the - * local ns, which does its own mesh-wide redistribution. RESUME_TX - * additionally releases this hop's flow-control token on the - * arrival link: per-hop counters advance in lockstep with the - * end-to-end ones since every packet of the flow transits here. - */ - if (cb->dst_node != qrtr_local_nid && - cb->dst_node != QRTR_NODE_BCAST && - (cb->type == QRTR_TYPE_DATA || cb->type == QRTR_TYPE_RESUME_TX)) { - struct sockaddr_qrtr from = {AF_QIPCRTR, - cb->src_node, cb->src_port}; - struct sockaddr_qrtr to = {AF_QIPCRTR, - cb->dst_node, cb->dst_port}; - struct qrtr_node *dst; - - dst = qrtr_node_lookup(cb->dst_node); - if (!dst || dst == node) { - if (dst) - qrtr_node_release(dst); - goto err; - } - - if (cb->type == QRTR_TYPE_RESUME_TX) { - struct sk_buff *clone; - - clone = skb_clone(skb, GFP_ATOMIC); - if (clone) - qrtr_tx_resume(node, clone); - } - - pr_debug("qrtr: fwd %u:%u -> %u:%u type %d len %zu\n", - cb->src_node, cb->src_port, - cb->dst_node, cb->dst_port, cb->type, size); - - if (skb_cow_head(skb, sizeof(struct qrtr_hdr_v1))) { - qrtr_node_release(dst); - goto err; - } - - qrtr_node_enqueue(dst, skb, cb->type, &from, &to); - qrtr_node_release(dst); - - return 0; - } - if (cb->type == QRTR_TYPE_RESUME_TX) { qrtr_tx_resume(node, skb); } else { diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index d650e0b0ba5b..67267304e7e9 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only snd-q6dsp-common-y := q6dsp-common.o q6dsp-lpass-ports.o q6dsp-lpass-clocks.o -snd-q6apm-y := q6apm.o audioreach.o topology.o q6apm-voice-proto.o +snd-q6apm-y := q6apm.o audioreach.o topology.o obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += snd-q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o diff --git a/sound/soc/qcom/qdsp6/audioreach.c b/sound/soc/qcom/qdsp6/audioreach.c index 4fea75b021e8..a13f753eff98 100644 --- a/sound/soc/qcom/qdsp6/audioreach.c +++ b/sound/soc/qcom/qdsp6/audioreach.c @@ -576,11 +576,10 @@ void *audioreach_alloc_graph_pkt(struct q6apm *apm, } EXPORT_SYMBOL_GPL(audioreach_alloc_graph_pkt); -int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, +int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode, - unsigned long timeout_s) + const struct gpr_pkt *pkt, uint32_t rsp_opcode) { const struct gpr_hdr *hdr = &pkt->hdr; @@ -602,9 +601,9 @@ int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, if (rsp_opcode) rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode) || - (result->opcode == rsp_opcode), timeout_s * HZ); + (result->opcode == rsp_opcode), 5 * HZ); else - rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), timeout_s * HZ); + rc = wait_event_timeout(*cmd_wait, (result->opcode == hdr->opcode), 5 * HZ); if (!rc) { dev_err(dev, "CMD timeout for [%x] opcode\n", hdr->opcode); @@ -621,16 +620,6 @@ err: mutex_unlock(cmd_lock); return rc; } -EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync_timeout); - -int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, - struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, - gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode) -{ - return audioreach_send_cmd_sync_timeout(dev, gdev, result, cmd_lock, - port, cmd_wait, pkt, rsp_opcode, 30); -} EXPORT_SYMBOL_GPL(audioreach_send_cmd_sync); int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, const struct gpr_pkt *pkt, diff --git a/sound/soc/qcom/qdsp6/audioreach.h b/sound/soc/qcom/qdsp6/audioreach.h index e52c4b564cbc..6859770b38a6 100644 --- a/sound/soc/qcom/qdsp6/audioreach.h +++ b/sound/soc/qcom/qdsp6/audioreach.h @@ -58,15 +58,12 @@ struct q6apm_graph; #define APM_CMD_GRAPH_FLUSH 0x01001005 #define APM_CMD_SET_CFG 0x01001006 #define APM_CMD_GET_CFG 0x01001007 -#define APM_CMD_REGISTER_CFG 0x01001008 #define APM_CMD_SHARED_MEM_MAP_REGIONS 0x0100100C #define APM_CMD_SHARED_MEM_UNMAP_REGIONS 0x0100100D #define APM_CMD_RSP_SHARED_MEM_MAP_REGIONS 0x02001001 #define APM_CMD_RSP_GET_CFG 0x02001000 #define APM_CMD_CLOSE_ALL 0x01001013 #define APM_CMD_REGISTER_SHARED_CFG 0x0100100A -#define AMDB_CMD_LOAD_MODULES 0x01001020 -#define AMDB_CMD_RSP_LOAD_MODULES 0x02001008 #define APM_MEMORY_MAP_SHMEM8_4K_POOL 3 @@ -845,11 +842,6 @@ void audioreach_graph_free_buf(struct q6apm_graph *graph); int audioreach_send_cmd_sync(struct device *dev, gpr_device_t *gdev, struct gpr_ibasic_rsp_result_t *result, struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, const struct gpr_pkt *pkt, uint32_t rsp_opcode); -int audioreach_send_cmd_sync_timeout(struct device *dev, gpr_device_t *gdev, - struct gpr_ibasic_rsp_result_t *result, - struct mutex *cmd_lock, gpr_port_t *port, wait_queue_head_t *cmd_wait, - const struct gpr_pkt *pkt, uint32_t rsp_opcode, - unsigned long timeout_s); int audioreach_graph_send_cmd_sync(struct q6apm_graph *graph, const struct gpr_pkt *pkt, uint32_t rsp_opcode); int audioreach_set_media_format(struct q6apm_graph *graph, diff --git a/sound/soc/qcom/qdsp6/q6apm-voice-proto.c b/sound/soc/qcom/qdsp6/q6apm-voice-proto.c deleted file mode 100644 index 32a2dfdd623a..000000000000 --- a/sound/soc/qcom/qdsp6/q6apm-voice-proto.c +++ /dev/null @@ -1,377 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Voice-call bring-up prototype for the Fairphone (Gen. 6): replay - * pre-generated APM command sequences through the q6apm GPR channel. - * - * The blobs reproduce, byte for byte, the GRAPH_OPEN/SET_CFG/PREPARE/START - * sequence the stock Android PAL/AGM/GSL stack sends to set up the - * handset voice-call graphs (mined from the device ACDB; generated by - * utilities/mkvoiceblobs.py in the bring-up repo). The modem's voice - * engine and the ADSP VCPM service wire up the vocoder themselves once - * these graphs are running. - * - * Local prototype only, NOT for upstream. Interface: - * echo > /sys/kernel/debug/q6apm-voice-proto/play - * where is relative to /lib/firmware. Playback aborts on the - * first command the DSP rejects. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "audioreach.h" -#include "q6apm.h" - -#define Q6VP_MAGIC 0x50563651 /* "Q6VP" little-endian */ -#define Q6VP_VERSION 1 - -/* - * A record opcode with this bit set is sent out-of-band: the payload is - * placed in an ADSP-mapped shared-memory region and the GPR command carries - * only an apm_cmd_header referencing it. Stock GSL sends every voice - * GRAPH_OPEN this way; it is mandatory because a voice graph must be opened - * atomically as one command (all subgraphs + cross-subgraph module - * connections and control links), and the whole payload (~4.3-4.7 KB) - * exceeds the ~4 KiB in-band GPR/GLINK intent limit. Splitting the open - * per-subgraph to fit in-band makes the cross-referencing TX DevicePP - * subgraph invalid (rejected at open) — see journal/calls.md 2026-07-08. - */ -#define Q6VP_OOB_FLAG 0x80000000 -/* - * A record opcode with this bit set carries the GPR destination port in the - * first payload word (stripped before sending). Lets a blob address static - * services other than APM — e.g. AMDB (port 3) module pre-loading, so the - * dynamic Fluence pp modules can be made resident BEFORE the voice - * GRAPH_OPENs. A first open that has to FastRPC-load them can fail or block - * so long that the client-side retry dance corrupts VCPM's per-VSID voice - * session (TX cal EBADPARAM / TX START EFAILED, journal/calls.md - * 2026-07-10). In-band records only. - */ -#define Q6VP_DSTPORT_FLAG 0x40000000 -#define Q6VP_GRAPH_ID 0xf000 /* private mem-map handle owner */ -#define Q6VP_BUF_SZ 0x800000 /* 8 MiB shared region */ -#define Q6VP_SCRATCH_SZ 0x10000 /* [0, 64K): transient commands */ -#define Q6VP_SID_MASK 0xf - -struct q6vp_hdr { - __le32 magic; - __le32 version; - __le32 num_records; -} __packed; - -struct q6vp_rec { - __le32 opcode; - __le32 size; -} __packed; - -static DEFINE_MUTEX(q6vp_play_lock); -static struct q6apm *q6vp_apm; -static struct dentry *q6vp_dir; -static struct device *q6vp_dais_dev; -static struct audioreach_graph_info *q6vp_info; -static void *q6vp_buf; -static dma_addr_t q6vp_buf_iova; -static phys_addr_t q6vp_buf_dsp_addr; - -static int q6vp_send(uint32_t opcode, const void *payload, uint32_t size) -{ - uint32_t dest_port = APM_MODULE_INSTANCE_ID; - uint32_t rsp_opcode = 0; - struct gpr_pkt *pkt; - int ret; - - if (opcode & Q6VP_DSTPORT_FLAG) { - if (size < sizeof(__le32)) - return -EINVAL; - dest_port = le32_to_cpup(payload); - payload += sizeof(__le32); - size -= sizeof(__le32); - opcode &= ~Q6VP_DSTPORT_FLAG; - } - - /* AMDB load responds with its own opcode, not an ibasic result */ - if (opcode == AMDB_CMD_LOAD_MODULES) - rsp_opcode = AMDB_CMD_RSP_LOAD_MODULES; - - pkt = audioreach_alloc_cmd_pkt(size, opcode, 0, GPR_APM_MODULE_IID, - dest_port); - if (IS_ERR(pkt)) - return PTR_ERR(pkt); - - memcpy((void *)pkt + GPR_HDR_SIZE + APM_CMD_HDR_SIZE, payload, size); - - /* - * Voice blobs need the long wait: a cold TX GRAPH_OPEN that has to - * FastRPC-load the Fluence pp modules takes >120 s. Regular audio - * commands (and especially the probe-time GET_SPF_STATE ready poll) - * must keep the short default or they hold the shared command mutex - * hostage at boot: a 240 s stall in apm_probe delays module loading - * past udev's worker timeout and the sound card never assembles. - */ - ret = q6apm_send_cmd_sync_timeout(q6vp_apm, pkt, rsp_opcode, 240); - kfree(pkt); - - return ret; -} - -/* - * Lazily set up the shared-memory region used for OOB commands: allocate a - * DMA buffer against the q6apm-dais child device (it carries the iommus - * mapping the ADSP expects, same as the PCM data path), register a private - * graph_info so the APM_CMD_RSP_SHARED_MEM_MAP_REGIONS callback has a slot - * to store the handle in, and map the region with the DSP. The mapping is - * kept until the module goes away. - */ -static int q6vp_oob_init(void) -{ - struct device *dev = q6vp_apm->dev; - struct of_phandle_args args; - struct platform_device *pdev; - struct device_node *np; - u64 sid = 0; - u32 graph_id = Q6VP_GRAPH_ID; - int ret; - - if (q6vp_info && q6vp_info->mem_map_handle) - return 0; - - if (!q6vp_dais_dev) { - np = of_get_compatible_child(dev->of_node, "qcom,q6apm-dais"); - if (!np) { - dev_err(dev, "voice-proto: no q6apm-dais node\n"); - return -ENODEV; - } - if (!of_parse_phandle_with_fixed_args(np, "iommus", 1, 0, - &args)) { - sid = args.args[0] & Q6VP_SID_MASK; - of_node_put(args.np); - } - pdev = of_find_device_by_node(np); - of_node_put(np); - if (!pdev) { - dev_err(dev, "voice-proto: no q6apm-dais device\n"); - return -ENODEV; - } - q6vp_dais_dev = &pdev->dev; - - q6vp_buf = dma_alloc_coherent(q6vp_dais_dev, Q6VP_BUF_SZ, - &q6vp_buf_iova, GFP_KERNEL); - if (!q6vp_buf) - return -ENOMEM; - q6vp_buf_dsp_addr = q6vp_buf_iova | (sid << 32); - } - - if (!q6vp_info) { - q6vp_info = kzalloc(sizeof(*q6vp_info), GFP_KERNEL); - if (!q6vp_info) - return -ENOMEM; - INIT_LIST_HEAD(&q6vp_info->sg_list); - q6vp_info->id = Q6VP_GRAPH_ID; - ret = idr_alloc_u32(&q6vp_apm->graph_info_idr, q6vp_info, - &graph_id, graph_id, GFP_KERNEL); - if (ret < 0) { - kfree(q6vp_info); - q6vp_info = NULL; - return ret; - } - } - - ret = q6apm_map_memory_fixed_region(q6vp_dais_dev, Q6VP_GRAPH_ID, - q6vp_buf_dsp_addr, Q6VP_BUF_SZ); - if (ret) { - dev_err(dev, "voice-proto: mem map failed (%d)\n", ret); - return ret; - } - - dev_info(dev, "voice-proto: OOB region mapped, handle 0x%x\n", - q6vp_info->mem_map_handle); - return 0; -} - -/* - * Persistent-slice bump offset: APM_CMD_REGISTER_CFG registers the payload - * with the DSP, which keeps reading that memory for as long as the config - * stays registered — those payloads must never be overwritten. They get - * bump-allocated slices above Q6VP_SCRATCH_SZ that live until reboot; - * transient commands (opens etc.) reuse the scratch slot at offset 0. - */ -static u32 q6vp_persist_off = Q6VP_SCRATCH_SZ; - -static int q6vp_send_oob(uint32_t opcode, const void *payload, uint32_t size) -{ - struct apm_cmd_header *cmd_header; - struct gpr_pkt *pkt; - u32 off = 0; - int ret; - - ret = q6vp_oob_init(); - if (ret) - return ret; - - if (opcode == APM_CMD_REGISTER_CFG) { - if (q6vp_persist_off + size > Q6VP_BUF_SZ) - return -EFBIG; - off = q6vp_persist_off; - q6vp_persist_off += ALIGN(size, SZ_4K); - } else if (size > Q6VP_SCRATCH_SZ) { - return -EFBIG; - } - - memcpy(q6vp_buf + off, payload, size); - - pkt = audioreach_alloc_apm_cmd_pkt(0, opcode, 0); - if (IS_ERR(pkt)) - return PTR_ERR(pkt); - - /* - * The region is mapped in absolute-address mode (mainline's - * q6apm_map_memory_fixed_region passes property_flag 0, unlike GSL - * which maps with IS_OFFSET_MODE and then references offset 0), so - * the header carries the full DSP-visible address of the buffer. - */ - cmd_header = (void *)pkt + GPR_HDR_SIZE; - cmd_header->payload_address_lsw = lower_32_bits(q6vp_buf_dsp_addr + off); - cmd_header->payload_address_msw = upper_32_bits(q6vp_buf_dsp_addr + off); - cmd_header->mem_map_handle = q6vp_info->mem_map_handle; - cmd_header->payload_size = size; - - ret = q6apm_send_cmd_sync_timeout(q6vp_apm, pkt, 0, 240); - kfree(pkt); - - return ret; -} - -static int q6vp_play(const char *name) -{ - const struct firmware *fw; - const struct q6vp_hdr *hdr; - const struct q6vp_rec *rec; - struct device *dev = q6vp_apm->dev; - size_t off; - uint32_t i, num, opcode, size; - int ret, err = 0; - - ret = request_firmware(&fw, name, dev); - if (ret) { - dev_err(dev, "voice-proto: cannot load %s (%d)\n", name, ret); - return ret; - } - - hdr = (const struct q6vp_hdr *)fw->data; - if (fw->size < sizeof(*hdr) || - le32_to_cpu(hdr->magic) != Q6VP_MAGIC || - le32_to_cpu(hdr->version) != Q6VP_VERSION) { - dev_err(dev, "voice-proto: %s: bad header\n", name); - ret = -EINVAL; - goto out; - } - - num = le32_to_cpu(hdr->num_records); - off = sizeof(*hdr); - for (i = 0; i < num; i++) { - if (off + sizeof(*rec) > fw->size) { - ret = -EINVAL; - goto out; - } - rec = (const struct q6vp_rec *)(fw->data + off); - opcode = le32_to_cpu(rec->opcode); - size = le32_to_cpu(rec->size); - off += sizeof(*rec); - if (off + size > fw->size) { - ret = -EINVAL; - goto out; - } - - if (opcode & Q6VP_OOB_FLAG) - ret = (opcode & Q6VP_DSTPORT_FLAG) ? -EINVAL : - q6vp_send_oob(opcode & ~Q6VP_OOB_FLAG, - fw->data + off, size); - else - ret = q6vp_send(opcode, fw->data + off, size); - dev_info(dev, "voice-proto: %s[%u] opcode 0x%08x size %u -> %d\n", - name, i, - opcode & ~(Q6VP_OOB_FLAG | Q6VP_DSTPORT_FLAG), - size, ret); - /* keep going on DSP rejections; each result is logged */ - if (ret) - err = ret; - - off += ALIGN(size, 4); - } - -out: - release_firmware(fw); - return ret ? ret : err; -} - -static ssize_t q6vp_play_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - char name[128]; - int ret; - - if (!q6vp_apm) - return -ENODEV; - if (count >= sizeof(name)) - return -EINVAL; - if (copy_from_user(name, ubuf, count)) - return -EFAULT; - name[count] = '\0'; - strim(name); - - /* - * Serialize blob playback: concurrent debugfs writers (e.g. a - * dropped ssh session whose write is still stuck in a DSP wait) - * would interleave their records on the GPR channel and corrupt - * both sequences (seen 2026-07-10). - */ - ret = mutex_lock_interruptible(&q6vp_play_lock); - if (ret) - return ret; - ret = q6vp_play(name); - mutex_unlock(&q6vp_play_lock); - - return ret ? ret : count; -} - -static const struct file_operations q6vp_play_fops = { - .open = simple_open, - .write = q6vp_play_write, - .llseek = default_llseek, -}; - -void q6apm_voice_proto_init(struct q6apm *apm) -{ - q6vp_apm = apm; - q6vp_dir = debugfs_create_dir("q6apm-voice-proto", NULL); - debugfs_create_file("play", 0200, q6vp_dir, NULL, &q6vp_play_fops); -} - -void q6apm_voice_proto_exit(void) -{ - debugfs_remove_recursive(q6vp_dir); - q6vp_dir = NULL; - - if (q6vp_info) { - if (q6vp_info->mem_map_handle) - q6apm_unmap_memory_fixed_region(q6vp_dais_dev, - Q6VP_GRAPH_ID); - idr_remove(&q6vp_apm->graph_info_idr, Q6VP_GRAPH_ID); - kfree(q6vp_info); - q6vp_info = NULL; - } - if (q6vp_buf) { - dma_free_coherent(q6vp_dais_dev, Q6VP_BUF_SZ, q6vp_buf, - q6vp_buf_iova); - q6vp_buf = NULL; - } - q6vp_dais_dev = NULL; - q6vp_apm = NULL; -} diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 6e0562e600dd..2ab378fb5032 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -38,16 +38,6 @@ int q6apm_send_cmd_sync(struct q6apm *apm, const struct gpr_pkt *pkt, NULL, &apm->wait, pkt, rsp_opcode); } -int q6apm_send_cmd_sync_timeout(struct q6apm *apm, const struct gpr_pkt *pkt, - uint32_t rsp_opcode, unsigned long timeout_s) -{ - gpr_device_t *gdev = apm->gdev; - - return audioreach_send_cmd_sync_timeout(&gdev->dev, gdev, &apm->result, - &apm->lock, NULL, &apm->wait, - pkt, rsp_opcode, timeout_s); -} - static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, uint32_t graph_id) { struct audioreach_graph_info *info; @@ -774,8 +764,6 @@ static int apm_probe(gpr_device_t *gdev) g_apm = apm; - q6apm_voice_proto_init(apm); - q6apm_get_apm_state(apm); ret = snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); @@ -793,7 +781,6 @@ static int apm_probe(gpr_device_t *gdev) static void apm_remove(gpr_device_t *gdev) { - q6apm_voice_proto_exit(); of_platform_depopulate(&gdev->dev); snd_soc_unregister_component(&gdev->dev); } @@ -830,7 +817,6 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) case GPR_BASIC_RSP_RESULT: switch (result->opcode) { case APM_CMD_SHARED_MEM_MAP_REGIONS: - case APM_CMD_REGISTER_CFG: case APM_CMD_GRAPH_START: case APM_CMD_GRAPH_OPEN: case APM_CMD_GRAPH_PREPARE: @@ -863,23 +849,6 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op) break; } break; - case AMDB_CMD_RSP_LOAD_MODULES: { - /* amdb_module_load_unload_t: proc_domain, error_code, - * num_modules, {module_id, handle_lsw, handle_msw}[]. - * A zero handle = module not registered with the AMDB. - */ - const u32 *amdb = data->payload; - u32 i, n = amdb[2]; - - for (i = 0; i < n; i++) - dev_info(dev, "AMDB load: module 0x%08x handle 0x%08x%08x\n", - amdb[3 + 3 * i], amdb[5 + 3 * i], - amdb[4 + 3 * i]); - apm->result.opcode = hdr->opcode; - apm->result.status = amdb[1]; - wake_up(&apm->wait); - break; - } case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: apm->result.opcode = hdr->opcode; apm->result.status = 0; diff --git a/sound/soc/qcom/qdsp6/q6apm.h b/sound/soc/qcom/qdsp6/q6apm.h index f8a66ff5f29f..376a36700c53 100644 --- a/sound/soc/qcom/qdsp6/q6apm.h +++ b/sound/soc/qcom/qdsp6/q6apm.h @@ -144,8 +144,6 @@ int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id); /* Helpers */ int q6apm_send_cmd_sync(struct q6apm *apm, const struct gpr_pkt *pkt, uint32_t rsp_opcode); -int q6apm_send_cmd_sync_timeout(struct q6apm *apm, const struct gpr_pkt *pkt, - uint32_t rsp_opcode, unsigned long timeout_s); /* Callback for graph specific */ struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, @@ -159,8 +157,4 @@ int q6apm_remove_initial_silence(struct device *dev, struct q6apm_graph *graph, int q6apm_remove_trailing_silence(struct device *dev, struct q6apm_graph *graph, uint32_t samples); int q6apm_set_real_module_id(struct device *dev, struct q6apm_graph *graph, uint32_t codec_id); int q6apm_get_hw_pointer(struct q6apm_graph *graph, int dir); - -/* FP6 voice-call bring-up prototype (q6apm-voice-proto.c) */ -void q6apm_voice_proto_init(struct q6apm *apm); -void q6apm_voice_proto_exit(void); #endif /* __APM_GRAPH_ */