From 81d3d3d0bf09e606dbc1e3daad1c7cef3976fca2 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:00 +0800 Subject: ASoC: codecs: add SoundWire mockup device support To test the host controller and bus management code, it is currently required to have a physical SoundWire peripheral attached to the bus. To help with pre-silicon or early hardware enablement, it would be very useful to have a SoundWire 'mockup' device that is exposed in platform firmware but does not drive any signal on the bus. This is different to the existing ASoC 'dummy' codec uses for I2S/TDM, the SoundWire spec makes it clear that a device that is not attached to the bus is not permitted to interact with the bus, be it for command/control or data. This patch exposes a 'mockup' device, with a minimalist driver, with 4 partID values reserved by Intel for such test configurations. The mockup device exposes one full-duplex DAI based on 2 ports (DP1 for playback and DP8 for capture). The capture data port is just virtual, such a mockup device is prevented by the SoundWire specification from presenting any data generated by a Source port without being Attached. All the callbacks exposed by the SoundWire Slave interface are populated, even if they just return immediately. This is intentional to describe what a minimal codec driver should do and implement and help new codec vendors provide support for their devices. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-2-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 18 +++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/sdw-mockup.c | 310 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 330 insertions(+) create mode 100644 sound/soc/codecs/sdw-mockup.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 7ebae3f09435..9e3e4db3d75d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -187,6 +187,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_RT715_SDCA_SDW imply SND_SOC_RT1308_SDW imply SND_SOC_RT1316_SDW + imply SND_SOC_SDW_MOCKUP imply SND_SOC_SGTL5000 imply SND_SOC_SI476X imply SND_SOC_SIMPLE_AMPLIFIER @@ -1287,6 +1288,23 @@ config SND_SOC_RT715_SDCA_SDW select REGMAP_SOUNDWIRE select REGMAP_SOUNDWIRE_MBQ +config SND_SOC_SDW_MOCKUP + tristate "SoundWire mockup codec" + depends on EXPERT + depends on SOUNDWIRE + help + This option enables a SoundWire mockup codec that does not drive the + bus, take part in the command/command protocol or generate data on a + Source port. + This option is only intended to be used for tests on a device + with a connector, in combination with a bus analyzer, or to test new + topologies that differ from the actual hardware layout. + This mockup device could be totally virtual but could also be a + real physical one with one key restriction: it is not allowed by the + SoundWire specification to be configured via a sideband mechanism and + generate audio data for capture. However, nothing prevents such a + peripheral device from snooping the bus. + #Freescale sgtl5000 codec config SND_SOC_SGTL5000 tristate "Freescale SGTL5000 CODEC" diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index de8b83dd2c76..d656b1405473 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -203,6 +203,7 @@ snd-soc-rt711-objs := rt711.o rt711-sdw.o snd-soc-rt711-sdca-objs := rt711-sdca.o rt711-sdca-sdw.o snd-soc-rt715-objs := rt715.o rt715-sdw.o snd-soc-rt715-sdca-objs := rt715-sdca.o rt715-sdca-sdw.o +snd-soc-sdw-mockup-objs := sdw-mockup.o snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-alc5623-objs := alc5623.o snd-soc-alc5632-objs := alc5632.o @@ -530,6 +531,7 @@ obj-$(CONFIG_SND_SOC_RT711) += snd-soc-rt711.o obj-$(CONFIG_SND_SOC_RT711_SDCA_SDW) += snd-soc-rt711-sdca.o obj-$(CONFIG_SND_SOC_RT715) += snd-soc-rt715.o obj-$(CONFIG_SND_SOC_RT715_SDCA_SDW) += snd-soc-rt715-sdca.o +obj-$(CONFIG_SND_SOC_SDW_MOCKUP) += snd-soc-sdw-mockup.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c new file mode 100644 index 000000000000..a4f79eb2c69d --- /dev/null +++ b/sound/soc/codecs/sdw-mockup.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// sdw-mockup.c -- a mockup SoundWire codec for tests where only the host +// drives the bus. +// +// Copyright(c) 2021 Intel Corporation +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct sdw_mockup_priv { + struct sdw_slave *slave; +}; + +struct sdw_stream_data { + struct sdw_stream_runtime *sdw_stream; +}; + +static int sdw_mockup_component_probe(struct snd_soc_component *component) +{ + return 0; +} + +static void sdw_mockup_component_remove(struct snd_soc_component *component) +{ +} + +static const struct snd_soc_component_driver snd_soc_sdw_mockup_component = { + .probe = sdw_mockup_component_probe, + .remove = sdw_mockup_component_remove, +}; + +static int sdw_mockup_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream, + int direction) +{ + struct sdw_stream_data *stream; + + if (!sdw_stream) + return 0; + + stream = kzalloc(sizeof(*stream), GFP_KERNEL); + if (!stream) + return -ENOMEM; + + stream->sdw_stream = sdw_stream; + + /* Use tx_mask or rx_mask to configure stream tag and set dma_data */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + dai->playback_dma_data = stream; + else + dai->capture_dma_data = stream; + + return 0; +} + +static void sdw_mockup_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sdw_stream_data *stream; + + stream = snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(stream); +} + +static int sdw_mockup_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sdw_mockup_priv *sdw_mockup = snd_soc_component_get_drvdata(component); + struct sdw_stream_config stream_config; + struct sdw_port_config port_config; + enum sdw_data_direction direction; + struct sdw_stream_data *stream; + int num_channels; + int port; + int ret; + + stream = snd_soc_dai_get_dma_data(dai, substream); + if (!stream) + return -EINVAL; + + if (!sdw_mockup->slave) + return -EINVAL; + + /* SoundWire specific configuration */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = SDW_DATA_DIR_RX; + port = 1; + } else { + direction = SDW_DATA_DIR_TX; + port = 8; + } + + stream_config.frame_rate = params_rate(params); + stream_config.ch_count = params_channels(params); + stream_config.bps = snd_pcm_format_width(params_format(params)); + stream_config.direction = direction; + + num_channels = params_channels(params); + port_config.ch_mask = (1 << num_channels) - 1; + port_config.num = port; + + ret = sdw_stream_add_slave(sdw_mockup->slave, &stream_config, + &port_config, 1, stream->sdw_stream); + if (ret) + dev_err(dai->dev, "Unable to configure port\n"); + + return ret; +} + +static int sdw_mockup_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sdw_mockup_priv *sdw_mockup = snd_soc_component_get_drvdata(component); + struct sdw_stream_data *stream = + snd_soc_dai_get_dma_data(dai, substream); + + if (!sdw_mockup->slave) + return -EINVAL; + + sdw_stream_remove_slave(sdw_mockup->slave, stream->sdw_stream); + return 0; +} + +static const struct snd_soc_dai_ops sdw_mockup_ops = { + .hw_params = sdw_mockup_pcm_hw_params, + .hw_free = sdw_mockup_pcm_hw_free, + .set_sdw_stream = sdw_mockup_set_sdw_stream, + .shutdown = sdw_mockup_shutdown, +}; + +static struct snd_soc_dai_driver sdw_mockup_dai[] = { + { + .name = "sdw-mockup-aif1", + .id = 1, + .playback = { + .stream_name = "DP1 Playback", + .channels_min = 1, + .channels_max = 2, + }, + .capture = { + .stream_name = "DP8 Capture", + .channels_min = 1, + .channels_max = 2, + }, + .ops = &sdw_mockup_ops, + }, +}; + +static int sdw_mockup_update_status(struct sdw_slave *slave, + enum sdw_slave_status status) +{ + return 0; +} + +static int sdw_mockup_read_prop(struct sdw_slave *slave) +{ + struct sdw_slave_prop *prop = &slave->prop; + int nval; + int i, j; + u32 bit; + unsigned long addr; + struct sdw_dpn_prop *dpn; + + prop->paging_support = false; + + /* + * first we need to allocate memory for set bits in port lists + * the port allocation is completely arbitrary: + * DP0 is not supported + * DP1 is sink + * DP8 is source + */ + prop->source_ports = BIT(8); + prop->sink_ports = BIT(1); + + nval = hweight32(prop->source_ports); + prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->src_dpn_prop), + GFP_KERNEL); + if (!prop->src_dpn_prop) + return -ENOMEM; + + i = 0; + dpn = prop->src_dpn_prop; + addr = prop->source_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[i].num = bit; + dpn[i].type = SDW_DPN_FULL; + dpn[i].simple_ch_prep_sm = true; + i++; + } + + /* do this again for sink now */ + nval = hweight32(prop->sink_ports); + prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, + sizeof(*prop->sink_dpn_prop), + GFP_KERNEL); + if (!prop->sink_dpn_prop) + return -ENOMEM; + + j = 0; + dpn = prop->sink_dpn_prop; + addr = prop->sink_ports; + for_each_set_bit(bit, &addr, 32) { + dpn[j].num = bit; + dpn[j].type = SDW_DPN_FULL; + dpn[j].simple_ch_prep_sm = true; + j++; + } + + prop->simple_clk_stop_capable = true; + + /* wake-up event */ + prop->wake_capable = 0; + + return 0; +} + +static int sdw_mockup_bus_config(struct sdw_slave *slave, + struct sdw_bus_params *params) +{ + return 0; +} + +static int sdw_mockup_interrupt_callback(struct sdw_slave *slave, + struct sdw_slave_intr_status *status) +{ + return 0; +} + +static const struct sdw_slave_ops sdw_mockup_slave_ops = { + .read_prop = sdw_mockup_read_prop, + .interrupt_callback = sdw_mockup_interrupt_callback, + .update_status = sdw_mockup_update_status, + .bus_config = sdw_mockup_bus_config, +}; + +static int sdw_mockup_sdw_probe(struct sdw_slave *slave, + const struct sdw_device_id *id) +{ + struct device *dev = &slave->dev; + struct sdw_mockup_priv *sdw_mockup; + int ret; + + sdw_mockup = devm_kzalloc(dev, sizeof(*sdw_mockup), GFP_KERNEL); + if (!sdw_mockup) + return -ENOMEM; + + dev_set_drvdata(dev, sdw_mockup); + sdw_mockup->slave = slave; + + ret = devm_snd_soc_register_component(dev, + &snd_soc_sdw_mockup_component, + sdw_mockup_dai, + ARRAY_SIZE(sdw_mockup_dai)); + + return ret; +} + +static int sdw_mockup_sdw_remove(struct sdw_slave *slave) +{ + return 0; +} + +/* + * Intel reserved parts ID with the following mapping expected: + * 0xAAAA: generic full-duplex codec + * 0xAA55: headset codec (mock-up of RT711/RT5682) - full-duplex + * 0x55AA: amplifier (mock-up of RT1308/Maxim 98373) - playback only with + * IV feedback + * 0x5555: mic codec (mock-up of RT715) - capture-only + */ +static const struct sdw_device_id sdw_mockup_id[] = { + SDW_SLAVE_ENTRY_EXT(0x0105, 0xAAAA, 0x0, 0, 0), + SDW_SLAVE_ENTRY_EXT(0x0105, 0xAA55, 0x0, 0, 0), + SDW_SLAVE_ENTRY_EXT(0x0105, 0x55AA, 0x0, 0, 0), + SDW_SLAVE_ENTRY_EXT(0x0105, 0x5555, 0x0, 0, 0), + {}, +}; +MODULE_DEVICE_TABLE(sdw, sdw_mockup_id); + +static struct sdw_driver sdw_mockup_sdw_driver = { + .driver = { + .name = "sdw-mockup", + .owner = THIS_MODULE, + }, + .probe = sdw_mockup_sdw_probe, + .remove = sdw_mockup_sdw_remove, + .ops = &sdw_mockup_slave_ops, + .id_table = sdw_mockup_id, +}; +module_sdw_driver(sdw_mockup_sdw_driver); + +MODULE_DESCRIPTION("ASoC SDW mockup codec driver"); +MODULE_AUTHOR("Pierre-Louis Bossart "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2694cda7a4393fbd436e28474832a053e70e0733 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:01 +0800 Subject: ASoC: soc-acpi: cnl: add table for SoundWire mockup devices Add support for two configurations with SoundWire mockup devices that emulate the two CometLake configurations with one and two amps. This patch helps test the SOF firmware on an UpExtreme board without any hardware connected, e.g. by doing a loopback of the playback stream on capture streams. The mapping of the partIDs is as follows: 0xAAAA: generic full-duplex codec (not currently used) 0xAA55: headset codec (mock-up of RT711/RT5682) - full-duplex 0x55AA: amplifier (mock-up of RT1308/RT1316/Maxim 98373) - playback with IV sense feedback 0x5555: mic codec (mock-up of RT715) - capture-only The tables are added in a separate file to allow for mockup codecs to be added on other platforms, but the mapping to specific topologies remains platform-specific. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-3-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/Makefile | 3 +- sound/soc/intel/common/soc-acpi-intel-cnl-match.c | 15 ++ .../intel/common/soc-acpi-intel-sdw-mockup-match.c | 166 +++++++++++++++++++++ .../intel/common/soc-acpi-intel-sdw-mockup-match.h | 17 +++ 4 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c create mode 100644 sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index 12a205ccdeeb..fef0b2d1de68 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -9,7 +9,8 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-cml-match.o soc-acpi-intel-icl-match.o \ soc-acpi-intel-tgl-match.o soc-acpi-intel-ehl-match.o \ soc-acpi-intel-jsl-match.o soc-acpi-intel-adl-match.o \ - soc-acpi-intel-hda-match.o + soc-acpi-intel-hda-match.o \ + soc-acpi-intel-sdw-mockup-match.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 39dad32564e6..94b650767e11 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -9,6 +9,7 @@ #include #include #include "../skylake/skl.h" +#include "soc-acpi-intel-sdw-mockup-match.h" static struct skl_machine_pdata cnl_pdata = { .use_tplg_pcm = true, @@ -60,6 +61,20 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[] = { .sof_fw_filename = "sof-cnl.ri", .sof_tplg_filename = "sof-cnl-rt5682-sdw2.tplg" }, + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-cnl.ri", + .sof_tplg_filename = "sof-cml-rt711-rt1308-mono-rt715.tplg", + }, {} }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_cnl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c new file mode 100644 index 000000000000..a3d33997736a --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// soc-acpi-intel-sdw-mockup-match.c - tables and support for SoundWire +// mockup device ACPI enumeration. +// +// Copyright (c) 2021, Intel Corporation. +// + +#include +#include +#include "soc-acpi-intel-sdw-mockup-match.h" + +static const struct snd_soc_acpi_endpoint sdw_mockup_single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_endpoint sdw_mockup_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint sdw_mockup_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_headset_0_adr[] = { + { + .adr = 0x0000000105AA5500ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_headset0" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_headset_1_adr[] = { + { + .adr = 0x0001000105AA5500ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_headset1" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_amp_1_adr[] = { + { + .adr = 0x000100010555AA00ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_amp1" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_amp_2_adr[] = { + { + .adr = 0x000200010555AA00ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_amp2" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_mic_0_adr[] = { + { + .adr = 0x0000000105555500ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_mic0" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_mic_3_adr[] = { + { + .adr = 0x0003000105555500ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_single_endpoint, + .name_prefix = "sdw_mockup_mic3" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_amp_1_group1_adr[] = { + { + .adr = 0x000100010555AA00ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_l_endpoint, + .name_prefix = "sdw_mockup_amp1_l" + } +}; + +static const struct snd_soc_acpi_adr_device sdw_mockup_amp_2_group1_adr[] = { + { + .adr = 0x000200010555AA00ull, + .num_endpoints = 1, + .endpoints = &sdw_mockup_r_endpoint, + .name_prefix = "sdw_mockup_amp2_r" + } +}; + +const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(sdw_mockup_headset_0_adr), + .adr_d = sdw_mockup_headset_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(sdw_mockup_amp_1_adr), + .adr_d = sdw_mockup_amp_1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(sdw_mockup_mic_3_adr), + .adr_d = sdw_mockup_mic_3_adr, + }, + {} +}; + +const struct snd_soc_acpi_link_adr sdw_mockup_headset_2amps_mic[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(sdw_mockup_headset_0_adr), + .adr_d = sdw_mockup_headset_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(sdw_mockup_amp_1_group1_adr), + .adr_d = sdw_mockup_amp_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(sdw_mockup_amp_2_group1_adr), + .adr_d = sdw_mockup_amp_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(sdw_mockup_mic_3_adr), + .adr_d = sdw_mockup_mic_3_adr, + }, + {} +}; + +const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(sdw_mockup_headset_1_adr), + .adr_d = sdw_mockup_headset_1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(sdw_mockup_amp_2_adr), + .adr_d = sdw_mockup_amp_2_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(sdw_mockup_mic_0_adr), + .adr_d = sdw_mockup_mic_0_adr, + }, + {} +}; diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h new file mode 100644 index 000000000000..c99eecd19e03 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-sdw-mockup-match.h - tables and support for SoundWire + * mockup device ACPI enumeration. + * + * Copyright (c) 2021, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_SDW_MOCKUP_MATCH +#define _SND_SOC_ACPI_INTEL_SDW_MOCKUP_MATCH + +extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[]; +extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_2amps_mic[]; +extern const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[]; + +#endif -- cgit v1.2.3 From 3025d398c436d313f9b6b5c1f53918efeafcf5dc Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:02 +0800 Subject: ASoC: soc-acpi: tgl: add table for SoundWire mockup devices Follow the same idea as for CNL/UpExtreme and add mockup test first. They will only be selected if the SSDT is modified to add such mockup devices. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-4-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/common/soc-acpi-intel-tgl-match.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 66595e3ab13f..e2488f0eaff8 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -8,6 +8,7 @@ #include #include +#include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs tgl_codecs = { .num_codecs = 1, @@ -351,6 +352,28 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { + /* mockup tests need to be first */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(2), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_fw_filename = "sof-tgl.ri", + .sof_tplg_filename = "sof-tgl-rt715-rt711-rt1308-mono.tplg", + }, { .link_mask = 0x7, .links = tgl_sdw_rt711_link1_rt1308_link2_rt715_link0, -- cgit v1.2.3 From 0ccac3bcf3564cbcba483dec20c7550939873f59 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:03 +0800 Subject: ASoC: Intel: boards: sof_sdw: add SoundWire mockup codecs for tests Add support for SoundWire mockup devices. The configurations assume the same topology as the CML SoundWire devices and can be used to test the SOF firmware on a development board (RVP, UpExtreme) without any hardware connected. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-5-yung-chuan.liao@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/intel/boards/Kconfig | 1 + sound/soc/intel/boards/sof_sdw.c | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 7e29b0d911e2..046955bf717c 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -602,6 +602,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_DMIC select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_SOF_MAXIM_COMMON + select SND_SOC_SDW_MOCKUP help Add support for Intel SoundWire-based platforms connected to MAX98373, RT700, RT711, RT1308 and RT715 diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 1a867c73a48e..82d909ef7a97 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -328,6 +328,19 @@ static const struct snd_soc_ops sdw_ops = { .shutdown = sdw_shutdown, }; +static int sof_sdw_mic_codec_mockup_init(const struct snd_soc_acpi_link_adr *link, + struct snd_soc_dai_link *dai_links, + struct sof_sdw_codec_info *info, + bool playback) +{ + /* + * force DAI link to use same ID as RT715 and DMIC + * to reuse topologies + */ + dai_links->id = SDW_DMIC_DAI_ID; + return 0; +} + static struct sof_sdw_codec_info codec_info_list[] = { { .part_id = 0x700, @@ -410,6 +423,34 @@ static struct sof_sdw_codec_info codec_info_list[] = { .dai_name = "rt5682-sdw", .init = sof_sdw_rt5682_init, }, + { + .part_id = 0xaaaa, /* generic codec mockup */ + .version_id = 0, + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .init = NULL, + }, + { + .part_id = 0xaa55, /* headset codec mockup */ + .version_id = 0, + .direction = {true, true}, + .dai_name = "sdw-mockup-aif1", + .init = NULL, + }, + { + .part_id = 0x55aa, /* amplifier mockup */ + .version_id = 0, + .direction = {true, false}, + .dai_name = "sdw-mockup-aif1", + .init = NULL, + }, + { + .part_id = 0x5555, + .version_id = 0, + .direction = {false, true}, + .dai_name = "sdw-mockup-aif1", + .init = sof_sdw_mic_codec_mockup_init, + }, }; static inline int find_codec_info_part(u64 adr) -- cgit v1.2.3 From 05d58bb65607bde24f867d85d27b48c4954e1442 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 28 Jun 2021 17:45:08 -0700 Subject: dt-bindings: phy: qcom,qmp: Add sc8180x PCIe compatible Add a compatible for the sc8180x PCIe PHY. Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210629004509.1788286-1-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml index f0497b8623ad..242560ff52a4 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml @@ -27,6 +27,7 @@ properties: - qcom,msm8998-qmp-ufs-phy - qcom,msm8998-qmp-usb3-phy - qcom,sc7180-qmp-usb3-phy + - qcom,sc8180x-qmp-pcie-phy - qcom,sc8180x-qmp-ufs-phy - qcom,sc8180x-qmp-usb3-phy - qcom,sdm845-qhp-pcie-phy @@ -326,6 +327,7 @@ allOf: compatible: contains: enum: + - qcom,sc8180x-qmp-pcie-phy - qcom,sdm845-qhp-pcie-phy - qcom,sdm845-qmp-pcie-phy - qcom,sdx55-qmp-pcie-phy -- cgit v1.2.3 From f839f14e24f27ccb1b822dd52f2ff4db340da52a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 28 Jun 2021 17:45:09 -0700 Subject: phy: qcom-qmp: Add sc8180x PCIe support The Qualcomm SC8180x platform has 4 PCIe controllers and PHYs, typically used to connect things such as a modem or NVME storage device. Add the programming sequence to get the PHYs up and running. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210629004509.1788286-2-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 140 ++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index cfe359488f5c..655bdef26143 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -2035,6 +2035,113 @@ static const struct qmp_phy_init_tbl qmp_v4_dp_tx_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_TX_TX_EMP_POST1_LVL, 0x20), }; +static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CORECLK_DIV_MODE1, 0x08), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP_EN, 0x42), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE0, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE2_MODE1, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE1_MODE1, 0xb4), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_VCO_TUNE_MAP, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_HSCLK_SEL, 0x11), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE0, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE0, 0x55), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE0, 0x1a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE0, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DEC_START_MODE1, 0x68), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START3_MODE1, 0x02), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START2_MODE1, 0xaa), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_DIV_FRAC_START1_MODE1, 0xab), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP2_MODE1, 0x34), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_LOCK_CMP1_MODE1, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_HSCLK_SEL, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE0, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE0, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CP_CTRL_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_PLL_CCTRL_MODE1, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE0, 0x1e), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE0, 0xca), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE2_MODE1, 0x18), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_BIN_VCOCAL_CMP_CODE1_MODE1, 0xa2), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_BUF_ENABLE, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_EN_CENTER, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER1, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_PER2, 0x01), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE0, 0xde), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE0, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE1_MODE1, 0x4c), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_SSC_STEP_SIZE2_MODE1, 0x06), + QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_ENABLE1, 0x90), +}; + +static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_TX_RCV_DETECT_LVL_2, 0x12), + QMP_PHY_INIT_CFG(QSERDES_V4_TX_LANE_MODE_1, 0x5), +}; + +static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_CNTRL, 0x03), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_ENABLES, 0x1c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_SIGDET_DEGLITCH_CNTRL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL1, 0x07), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL2, 0x6e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL3, 0x6e), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQU_ADAPTOR_CNTRL4, 0x4a), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DFE_EN_TIMER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_PI_CONTROLS, 0x70), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x17), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL1, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_VGA_CAL_CNTRL2, 0x37), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_LOW, 0xd4), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH, 0x54), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH2, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH3, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_10_HIGH4, 0x31), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_LOW, 0x24), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH, 0xe4), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH2, 0xec), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH3, 0x39), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_01_HIGH4, 0x36), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_LOW, 0x7f), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH2, 0xff), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH3, 0xdb), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_MODE_00_HIGH4, 0x75), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_HIGH, 0x00), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RX_IDAC_TSETTLE_LOW, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_AUX_DATA_TCOARSE_TFINE, 0xa0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_RCLK_AUXDATA_SEL, 0xc0), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_DCC_CTRL1, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_GM_CAL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_FO_GAIN, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_V4_RX_UCDR_SO_GAIN, 0x03), +}; + +static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_P2U3_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RX_SIGDET_LVL, 0xaa), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_RATE_SLEW_CNTRL1, 0x0b), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_REFGEN_REQ_CONFIG1, 0x0d), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_EQ_CONFIG5, 0x01), +}; + +static const struct qmp_phy_init_tbl sc8180x_qmp_pcie_pcs_misc_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_OSC_DTCT_ACTIONS, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P1_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_L1P2_WAKEUP_DLY_TIME_AUXCLK_L, 0x01), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_INT_AUX_CLK_CONFIG1, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_PRE, 0x00), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_PRESET_P10_POST, 0x58), + QMP_PHY_INIT_CFG(QPHY_V4_PCS_PCIE_ENDPOINT_REFCLK_DRIVE, 0xc1), +}; + static const struct qmp_phy_init_tbl sm8250_qmp_pcie_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V4_COM_SYSCLK_EN_SEL, 0x08), QMP_PHY_INIT_CFG(QSERDES_V4_COM_CLK_SELECT, 0x34), @@ -3399,6 +3506,36 @@ static const struct qmp_phy_cfg sm8150_usb3phy_cfg = { .is_dual_lane_phy = true, }; +static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { + .type = PHY_TYPE_PCIE, + .nlanes = 1, + + .serdes_tbl = sm8250_qmp_pcie_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl), + .tx_tbl = sc8180x_qmp_pcie_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl), + .rx_tbl = sc8180x_qmp_pcie_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_rx_tbl), + .pcs_tbl = sc8180x_qmp_pcie_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_tbl), + .pcs_misc_tbl = sc8180x_qmp_pcie_pcs_misc_tbl, + .pcs_misc_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_pcs_misc_tbl), + .clk_list = sdm845_pciephy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_pciephy_clk_l), + .reset_list = sdm845_pciephy_reset_l, + .num_resets = ARRAY_SIZE(sdm845_pciephy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = sm8250_pcie_regs_layout, + + .start_ctrl = PCS_START | SERDES_START, + .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, + + .has_pwrdn_delay = true, + .pwrdn_delay_min = 995, /* us */ + .pwrdn_delay_max = 1005, /* us */ +}; + static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -5231,6 +5368,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sc7180-qmp-usb3-dp-phy", /* It's a combo phy */ + }, { + .compatible = "qcom,sc8180x-qmp-pcie-phy", + .data = &sc8180x_pciephy_cfg, }, { .compatible = "qcom,sc8180x-qmp-ufs-phy", .data = &sm8150_ufsphy_cfg, -- cgit v1.2.3 From 057d445b9ef22c0c17fad46beb82146c9f0574c0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 14 Jul 2021 11:42:13 +0200 Subject: dt-bindings: phy: Rename Intel Keem Bay USB PHY bindings This is the only file not using the "intel,keembay-*" pattern. Fortunately the actual compatible value is already following the standard scheme. Fixes: 4086afa2a1627939 ("dt-bindings: phy: Add Intel Keem Bay USB PHY bindings") Signed-off-by: Geert Uytterhoeven Acked-by: Rob Herring Link: https://lore.kernel.org/r/91235a64185f7446fc58e638d77691078d3114d1.1626255556.git.geert+renesas@glider.be Signed-off-by: Vinod Koul --- .../bindings/phy/intel,keembay-phy-usb.yaml | 44 ++++++++++++++++++++++ .../bindings/phy/intel,phy-keembay-usb.yaml | 44 ---------------------- 2 files changed, 44 insertions(+), 44 deletions(-) create mode 100644 Documentation/devicetree/bindings/phy/intel,keembay-phy-usb.yaml delete mode 100644 Documentation/devicetree/bindings/phy/intel,phy-keembay-usb.yaml diff --git a/Documentation/devicetree/bindings/phy/intel,keembay-phy-usb.yaml b/Documentation/devicetree/bindings/phy/intel,keembay-phy-usb.yaml new file mode 100644 index 000000000000..52815b6c2b88 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/intel,keembay-phy-usb.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/intel,keembay-phy-usb.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Intel Keem Bay USB PHY bindings + +maintainers: + - Wan Ahmad Zainie + +properties: + compatible: + const: intel,keembay-usb-phy + + reg: + items: + - description: USB APB CPR (clock, power, reset) register + - description: USB APB slave register + + reg-names: + items: + - const: cpr-apb-base + - const: slv-apb-base + + '#phy-cells': + const: 0 + +required: + - compatible + - reg + - '#phy-cells' + +additionalProperties: false + +examples: + - | + usb-phy@20400000 { + compatible = "intel,keembay-usb-phy"; + reg = <0x20400000 0x1c>, + <0x20480000 0xd0>; + reg-names = "cpr-apb-base", "slv-apb-base"; + #phy-cells = <0>; + }; diff --git a/Documentation/devicetree/bindings/phy/intel,phy-keembay-usb.yaml b/Documentation/devicetree/bindings/phy/intel,phy-keembay-usb.yaml deleted file mode 100644 index a217bb8ac5bc..000000000000 --- a/Documentation/devicetree/bindings/phy/intel,phy-keembay-usb.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/phy/intel,phy-keembay-usb.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Intel Keem Bay USB PHY bindings - -maintainers: - - Wan Ahmad Zainie - -properties: - compatible: - const: intel,keembay-usb-phy - - reg: - items: - - description: USB APB CPR (clock, power, reset) register - - description: USB APB slave register - - reg-names: - items: - - const: cpr-apb-base - - const: slv-apb-base - - '#phy-cells': - const: 0 - -required: - - compatible - - reg - - '#phy-cells' - -additionalProperties: false - -examples: - - | - usb-phy@20400000 { - compatible = "intel,keembay-usb-phy"; - reg = <0x20400000 0x1c>, - <0x20480000 0xd0>; - reg-names = "cpr-apb-base", "slv-apb-base"; - #phy-cells = <0>; - }; -- cgit v1.2.3 From b95637e2da155cb3111d008e3c5d641b4dcf5000 Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Fri, 9 Jul 2021 18:45:23 +0900 Subject: phy: samsung-ufs: move phy-exynos7-ufs header Instead of using exynos7 ufs definition in phy-exynos7-ufs.h, we should put it into phy-exynos7-ufs.c to be included different objects or units. Suggested-by: Krzysztof Kozlowski Signed-off-by: Chanho Park Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210709094524.110193-2-chanho61.park@samsung.com Signed-off-by: Vinod Koul --- drivers/phy/samsung/Makefile | 4 +- drivers/phy/samsung/phy-exynos7-ufs.c | 77 +++++++++++++++++++++++++++++++++ drivers/phy/samsung/phy-exynos7-ufs.h | 81 ----------------------------------- drivers/phy/samsung/phy-samsung-ufs.h | 5 ++- 4 files changed, 84 insertions(+), 83 deletions(-) create mode 100644 drivers/phy/samsung/phy-exynos7-ufs.c delete mode 100644 drivers/phy/samsung/phy-exynos7-ufs.h diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile index 3959100fe8a2..68518ae30c1b 100644 --- a/drivers/phy/samsung/Makefile +++ b/drivers/phy/samsung/Makefile @@ -2,7 +2,9 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o -obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-samsung-ufs.o +obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-exynos-ufs.o +phy-exynos-ufs-y += phy-samsung-ufs.o +phy-exynos-ufs-y += phy-exynos7-ufs.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o diff --git a/drivers/phy/samsung/phy-exynos7-ufs.c b/drivers/phy/samsung/phy-exynos7-ufs.c new file mode 100644 index 000000000000..7c9008e163db --- /dev/null +++ b/drivers/phy/samsung/phy-exynos7-ufs.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS PHY driver data for Samsung EXYNOS7 SoC + * + * Copyright (C) 2020 Samsung Electronics Co., Ltd. + */ + +#include "phy-samsung-ufs.h" + +#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL 0x720 +#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1 +#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0) + +/* Calibration for phy initialization */ +static const struct samsung_ufs_phy_cfg exynos7_pre_init_cfg[] = { + PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x017, 0x84, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x035, 0x58, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x037, 0x40, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x03b, 0x83, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x04c, 0x5b, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x05c, 0x14, PWR_MODE_ANY), + END_UFS_PHY_CFG +}; + +/* Calibration for HS mode series A/B */ +static const struct samsung_ufs_phy_cfg exynos7_pre_pwr_hs_cfg[] = { + PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_HS_ANY), + PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_HS_ANY), + PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_HS_ANY), + /* Setting order: 1st(0x16, 2nd(0x15) */ + PHY_COMN_REG_CFG(0x016, 0xff, PWR_MODE_HS_ANY), + PHY_COMN_REG_CFG(0x015, 0x80, PWR_MODE_HS_ANY), + PHY_COMN_REG_CFG(0x017, 0x94, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x037, 0x43, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x038, 0x3f, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_HS_G2_SER_A), + PHY_TRSV_REG_CFG(0x042, 0xbb, PWR_MODE_HS_G2_SER_B), + PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x034, 0x35, PWR_MODE_HS_G2_SER_A), + PHY_TRSV_REG_CFG(0x034, 0x36, PWR_MODE_HS_G2_SER_B), + PHY_TRSV_REG_CFG(0x035, 0x5b, PWR_MODE_HS_G2_SER_A), + PHY_TRSV_REG_CFG(0x035, 0x5c, PWR_MODE_HS_G2_SER_B), + END_UFS_PHY_CFG +}; + +/* Calibration for HS mode series A/B atfer PMC */ +static const struct samsung_ufs_phy_cfg exynos7_post_pwr_hs_cfg[] = { + PHY_COMN_REG_CFG(0x015, 0x00, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_HS_ANY), + END_UFS_PHY_CFG +}; + +static const struct samsung_ufs_phy_cfg *exynos7_ufs_phy_cfgs[CFG_TAG_MAX] = { + [CFG_PRE_INIT] = exynos7_pre_init_cfg, + [CFG_PRE_PWR_HS] = exynos7_pre_pwr_hs_cfg, + [CFG_POST_PWR_HS] = exynos7_post_pwr_hs_cfg, +}; + +const struct samsung_ufs_phy_drvdata exynos7_ufs_phy = { + .cfg = exynos7_ufs_phy_cfgs, + .isol = { + .offset = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL, + .mask = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK, + .en = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN, + }, + .has_symbol_clk = 1, +}; diff --git a/drivers/phy/samsung/phy-exynos7-ufs.h b/drivers/phy/samsung/phy-exynos7-ufs.h deleted file mode 100644 index 518923141958..000000000000 --- a/drivers/phy/samsung/phy-exynos7-ufs.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * UFS PHY driver data for Samsung EXYNOS7 SoC - * - * Copyright (C) 2020 Samsung Electronics Co., Ltd. - */ -#ifndef _PHY_EXYNOS7_UFS_H_ -#define _PHY_EXYNOS7_UFS_H_ - -#include "phy-samsung-ufs.h" - -#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL 0x720 -#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1 -#define EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0) - -/* Calibration for phy initialization */ -static const struct samsung_ufs_phy_cfg exynos7_pre_init_cfg[] = { - PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_ANY), - PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_ANY), - PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_ANY), - PHY_COMN_REG_CFG(0x017, 0x84, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x035, 0x58, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x037, 0x40, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x03b, 0x83, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x04c, 0x5b, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_ANY), - PHY_TRSV_REG_CFG(0x05c, 0x14, PWR_MODE_ANY), - END_UFS_PHY_CFG -}; - -/* Calibration for HS mode series A/B */ -static const struct samsung_ufs_phy_cfg exynos7_pre_pwr_hs_cfg[] = { - PHY_COMN_REG_CFG(0x00f, 0xfa, PWR_MODE_HS_ANY), - PHY_COMN_REG_CFG(0x010, 0x82, PWR_MODE_HS_ANY), - PHY_COMN_REG_CFG(0x011, 0x1e, PWR_MODE_HS_ANY), - /* Setting order: 1st(0x16, 2nd(0x15) */ - PHY_COMN_REG_CFG(0x016, 0xff, PWR_MODE_HS_ANY), - PHY_COMN_REG_CFG(0x015, 0x80, PWR_MODE_HS_ANY), - PHY_COMN_REG_CFG(0x017, 0x94, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x036, 0x32, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x037, 0x43, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x038, 0x3f, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x042, 0x88, PWR_MODE_HS_G2_SER_A), - PHY_TRSV_REG_CFG(0x042, 0xbb, PWR_MODE_HS_G2_SER_B), - PHY_TRSV_REG_CFG(0x043, 0xa6, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x048, 0x74, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x034, 0x35, PWR_MODE_HS_G2_SER_A), - PHY_TRSV_REG_CFG(0x034, 0x36, PWR_MODE_HS_G2_SER_B), - PHY_TRSV_REG_CFG(0x035, 0x5b, PWR_MODE_HS_G2_SER_A), - PHY_TRSV_REG_CFG(0x035, 0x5c, PWR_MODE_HS_G2_SER_B), - END_UFS_PHY_CFG -}; - -/* Calibration for HS mode series A/B atfer PMC */ -static const struct samsung_ufs_phy_cfg exynos7_post_pwr_hs_cfg[] = { - PHY_COMN_REG_CFG(0x015, 0x00, PWR_MODE_HS_ANY), - PHY_TRSV_REG_CFG(0x04d, 0x83, PWR_MODE_HS_ANY), - END_UFS_PHY_CFG -}; - -static const struct samsung_ufs_phy_cfg *exynos7_ufs_phy_cfgs[CFG_TAG_MAX] = { - [CFG_PRE_INIT] = exynos7_pre_init_cfg, - [CFG_PRE_PWR_HS] = exynos7_pre_pwr_hs_cfg, - [CFG_POST_PWR_HS] = exynos7_post_pwr_hs_cfg, -}; - -static struct samsung_ufs_phy_drvdata exynos7_ufs_phy = { - .cfg = exynos7_ufs_phy_cfgs, - .isol = { - .offset = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL, - .mask = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_MASK, - .en = EXYNOS7_EMBEDDED_COMBO_PHY_CTRL_EN, - }, - .has_symbol_clk = 1, -}; - -#endif /* _PHY_EXYNOS7_UFS_H_ */ diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h index 5de78710524c..5ab6ca6fa187 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -10,6 +10,9 @@ #ifndef _PHY_SAMSUNG_UFS_ #define _PHY_SAMSUNG_UFS_ +#include +#include + #define PHY_COMN_BLK 1 #define PHY_TRSV_BLK 2 #define END_UFS_PHY_CFG { 0 } @@ -134,6 +137,6 @@ static inline void samsung_ufs_phy_ctrl_isol( phy->isol->mask, isol ? 0 : phy->isol->en); } -#include "phy-exynos7-ufs.h" +extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy; #endif /* _PHY_SAMSUNG_UFS_ */ -- cgit v1.2.3 From d64519249e1d5520e8420936d662ec2cfb155dfc Mon Sep 17 00:00:00 2001 From: Chanho Park Date: Fri, 9 Jul 2021 18:45:24 +0900 Subject: phy: samsung-ufs: support exynosauto ufs phy driver This patch adds to support phy-exynosautov9-ufs driver for ExynosAuto v9 series SoCs. The patch adds "samsung,exynosautov9-ufs-phy" compatible. Unlike previous exynos ufs phy, the chip uses 0x50 offset as PHY_TRSV_REG_CFG_OFFSET. Signed-off-by: Chanho Park Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210709094524.110193-3-chanho61.park@samsung.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/samsung,ufs-phy.yaml | 1 + drivers/phy/samsung/Makefile | 1 + drivers/phy/samsung/phy-exynosautov9-ufs.c | 67 ++++++++++++++++++++++ drivers/phy/samsung/phy-samsung-ufs.c | 3 + drivers/phy/samsung/phy-samsung-ufs.h | 8 ++- 5 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 drivers/phy/samsung/phy-exynosautov9-ufs.c diff --git a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml index 636cc501b54f..f6ed1a005e7a 100644 --- a/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml +++ b/Documentation/devicetree/bindings/phy/samsung,ufs-phy.yaml @@ -16,6 +16,7 @@ properties: compatible: enum: - samsung,exynos7-ufs-phy + - samsung,exynosautov9-ufs-phy reg: maxItems: 1 diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile index 68518ae30c1b..65e4cc59403f 100644 --- a/drivers/phy/samsung/Makefile +++ b/drivers/phy/samsung/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o obj-$(CONFIG_PHY_SAMSUNG_UFS) += phy-exynos-ufs.o phy-exynos-ufs-y += phy-samsung-ufs.o phy-exynos-ufs-y += phy-exynos7-ufs.o +phy-exynos-ufs-y += phy-exynosautov9-ufs.o obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o phy-exynos-usb2-y += phy-samsung-usb2.o phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o diff --git a/drivers/phy/samsung/phy-exynosautov9-ufs.c b/drivers/phy/samsung/phy-exynosautov9-ufs.c new file mode 100644 index 000000000000..36398a15c2db --- /dev/null +++ b/drivers/phy/samsung/phy-exynosautov9-ufs.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * UFS PHY driver data for Samsung EXYNOSAUTO v9 SoC + * + * Copyright (C) 2021 Samsung Electronics Co., Ltd. + */ + +#include "phy-samsung-ufs.h" + +#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL 0x728 +#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_MASK 0x1 +#define EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_EN BIT(0) + +#define PHY_TRSV_REG_CFG_AUTOV9(o, v, d) \ + PHY_TRSV_REG_CFG_OFFSET(o, v, d, 0x50) + +/* Calibration for phy initialization */ +static const struct samsung_ufs_phy_cfg exynosautov9_pre_init_cfg[] = { + PHY_COMN_REG_CFG(0x023, 0x80, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x01d, 0x10, PWR_MODE_ANY), + + PHY_TRSV_REG_CFG_AUTOV9(0x044, 0xb5, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x04d, 0x43, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x05b, 0x20, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x05e, 0xc0, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x038, 0x12, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x059, 0x58, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x06c, 0x18, PWR_MODE_ANY), + PHY_TRSV_REG_CFG_AUTOV9(0x06d, 0x02, PWR_MODE_ANY), + + PHY_COMN_REG_CFG(0x023, 0xc0, PWR_MODE_ANY), + PHY_COMN_REG_CFG(0x023, 0x00, PWR_MODE_ANY), + + PHY_TRSV_REG_CFG(0x042, 0x5d, PWR_MODE_ANY), + PHY_TRSV_REG_CFG(0x043, 0x80, PWR_MODE_ANY), + + END_UFS_PHY_CFG, +}; + +/* Calibration for HS mode series A/B */ +static const struct samsung_ufs_phy_cfg exynosautov9_pre_pwr_hs_cfg[] = { + PHY_TRSV_REG_CFG(0x032, 0xbc, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x03c, 0x7f, PWR_MODE_HS_ANY), + PHY_TRSV_REG_CFG(0x048, 0xc0, PWR_MODE_HS_ANY), + + PHY_TRSV_REG_CFG(0x04a, 0x00, PWR_MODE_HS_G3_SER_B), + PHY_TRSV_REG_CFG(0x04b, 0x10, PWR_MODE_HS_G1_SER_B | + PWR_MODE_HS_G3_SER_B), + PHY_TRSV_REG_CFG(0x04d, 0x63, PWR_MODE_HS_G3_SER_B), + + END_UFS_PHY_CFG, +}; + +static const struct samsung_ufs_phy_cfg *exynosautov9_ufs_phy_cfgs[CFG_TAG_MAX] = { + [CFG_PRE_INIT] = exynosautov9_pre_init_cfg, + [CFG_PRE_PWR_HS] = exynosautov9_pre_pwr_hs_cfg, +}; + +const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy = { + .cfg = exynosautov9_ufs_phy_cfgs, + .isol = { + .offset = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL, + .mask = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_MASK, + .en = EXYNOSAUTOV9_EMBEDDED_COMBO_PHY_CTRL_EN, + }, + .has_symbol_clk = 0, +}; diff --git a/drivers/phy/samsung/phy-samsung-ufs.c b/drivers/phy/samsung/phy-samsung-ufs.c index dd9ab1519d83..602ddef259eb 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.c +++ b/drivers/phy/samsung/phy-samsung-ufs.c @@ -347,6 +347,9 @@ static const struct of_device_id samsung_ufs_phy_match[] = { { .compatible = "samsung,exynos7-ufs-phy", .data = &exynos7_ufs_phy, + }, { + .compatible = "samsung,exynosautov9-ufs-phy", + .data = &exynosautov9_ufs_phy, }, {}, }; diff --git a/drivers/phy/samsung/phy-samsung-ufs.h b/drivers/phy/samsung/phy-samsung-ufs.h index 5ab6ca6fa187..91a0e9f94f98 100644 --- a/drivers/phy/samsung/phy-samsung-ufs.h +++ b/drivers/phy/samsung/phy-samsung-ufs.h @@ -27,14 +27,17 @@ .id = PHY_COMN_BLK, \ } -#define PHY_TRSV_REG_CFG(o, v, d) { \ +#define PHY_TRSV_REG_CFG_OFFSET(o, v, d, c) { \ .off_0 = PHY_APB_ADDR((o)), \ - .off_1 = PHY_APB_ADDR((o) + PHY_TRSV_CH_OFFSET), \ + .off_1 = PHY_APB_ADDR((o) + (c)), \ .val = (v), \ .desc = (d), \ .id = PHY_TRSV_BLK, \ } +#define PHY_TRSV_REG_CFG(o, v, d) \ + PHY_TRSV_REG_CFG_OFFSET(o, v, d, PHY_TRSV_CH_OFFSET) + /* UFS PHY registers */ #define PHY_PLL_LOCK_STATUS 0x1e #define PHY_CDR_LOCK_STATUS 0x5e @@ -138,5 +141,6 @@ static inline void samsung_ufs_phy_ctrl_isol( } extern const struct samsung_ufs_phy_drvdata exynos7_ufs_phy; +extern const struct samsung_ufs_phy_drvdata exynosautov9_ufs_phy; #endif /* _PHY_SAMSUNG_UFS_ */ -- cgit v1.2.3 From 2b9fc773c31bb7cb7529757382013a8158bf7e9c Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Sat, 26 Jun 2021 21:22:44 +0530 Subject: drivers: firmware: Add PDI load API support This patch adds load PDI API support to enable full/partial PDI loading from linux. Programmable Device Image (PDI) is combination of headers, images and bitstream files to be loaded. Reviewed-by: Moritz Fischer Signed-off-by: Nava kishore Manne Link: https://lore.kernel.org/r/20210626155248.5004-2-nava.manne@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/xilinx/zynqmp.c | 17 +++++++++++++++++ include/linux/firmware/xlnx-zynqmp.h | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 15b138326ecc..2db571da9ad8 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -1011,6 +1011,23 @@ int zynqmp_pm_set_requirement(const u32 node, const u32 capabilities, } EXPORT_SYMBOL_GPL(zynqmp_pm_set_requirement); +/** + * zynqmp_pm_load_pdi - Load and process PDI + * @src: Source device where PDI is located + * @address: PDI src address + * + * This function provides support to load PDI from linux + * + * Return: Returns status, either success or error+reason + */ +int zynqmp_pm_load_pdi(const u32 src, const u64 address) +{ + return zynqmp_pm_invoke_fn(PM_LOAD_PDI, src, + lower_32_bits(address), + upper_32_bits(address), 0, NULL); +} +EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi); + /** * zynqmp_pm_aes - Access AES hardware to encrypt/decrypt the data using * AES-GCM core. diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 9d1a5c175065..56b426fe020c 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -52,6 +52,10 @@ #define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U #define ZYNQMP_PM_CAPABILITY_UNUSABLE 0x8U +/* Loader commands */ +#define PM_LOAD_PDI 0x701 +#define PDI_SRC_DDR 0xF + /* * Firmware FPGA Manager flags * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration @@ -411,6 +415,7 @@ int zynqmp_pm_pinctrl_get_config(const u32 pin, const u32 param, u32 *value); int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, u32 value); +int zynqmp_pm_load_pdi(const u32 src, const u64 address); #else static inline int zynqmp_pm_get_api_version(u32 *version) { @@ -622,6 +627,11 @@ static inline int zynqmp_pm_pinctrl_set_config(const u32 pin, const u32 param, { return -ENODEV; } + +static inline int zynqmp_pm_load_pdi(const u32 src, const u64 address) +{ + return -ENODEV; +} #endif #endif /* __FIRMWARE_ZYNQMP_H__ */ -- cgit v1.2.3 From f9ac897e5a4bf7255f2f7613f2a74c2a9a41327c Mon Sep 17 00:00:00 2001 From: Appana Durga Kedareswara rao Date: Sat, 26 Jun 2021 21:22:45 +0530 Subject: dt-bindings: fpga: Add binding doc for versal fpga manager This patch adds binding doc for versal fpga manager driver. Reviewed-by: Rob Herring Signed-off-by: Nava kishore Manne Signed-off-by: Appana Durga Kedareswara rao Link: https://lore.kernel.org/r/20210626155248.5004-3-nava.manne@xilinx.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/fpga/xlnx,versal-fpga.yaml | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml diff --git a/Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml b/Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml new file mode 100644 index 000000000000..ac6a207278d5 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/xlnx,versal-fpga.yaml @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/fpga/xlnx,versal-fpga.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx Versal FPGA driver. + +maintainers: + - Nava kishore Manne + +description: | + Device Tree Versal FPGA bindings for the Versal SoC, controlled + using firmware interface. + +properties: + compatible: + items: + - enum: + - xlnx,versal-fpga + +required: + - compatible + +additionalProperties: false + +examples: + - | + versal_fpga: versal_fpga { + compatible = "xlnx,versal-fpga"; + }; + +... -- cgit v1.2.3 From f8cc6d715bfc649e523cc829d2e6d1e58b430a33 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Sat, 26 Jun 2021 21:22:46 +0530 Subject: dt-bindings: firmware: Add bindings for xilinx firmware Add documentation to describe Xilinx firmware driver bindings. Firmware driver provides an interface to firmware APIs. Interface APIs can be used by any driver to communicate to Platform Management Unit. Reviewed-by: Rob Herring Signed-off-by: Nava kishore Manne Link: https://lore.kernel.org/r/20210626155248.5004-4-nava.manne@xilinx.com Signed-off-by: Greg Kroah-Hartman --- .../firmware/xilinx/xlnx,zynqmp-firmware.yaml | 89 ++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml new file mode 100644 index 000000000000..f14f7b454f07 --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/firmware/xilinx/xlnx,zynqmp-firmware.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Xilinx firmware driver + +maintainers: + - Nava kishore Manne + +description: The zynqmp-firmware node describes the interface to platform + firmware. ZynqMP has an interface to communicate with secure firmware. + Firmware driver provides an interface to firmware APIs. Interface APIs + can be used by any driver to communicate to PMUFW(Platform Management Unit). + These requests include clock management, pin control, device control, + power management service, FPGA service and other platform management + services. + +properties: + compatible: + oneOf: + - description: For implementations complying for Zynq Ultrascale+ MPSoC. + const: xlnx,zynqmp-firmware + + - description: For implementations complying for Versal. + const: xlnx,versal-firmware + + method: + description: | + The method of calling the PM-API firmware layer. + Permitted values are. + - "smc" : SMC #0, following the SMCCC + - "hvc" : HVC #0, following the SMCCC + + $ref: /schemas/types.yaml#/definitions/string-array + enum: + - smc + - hvc + + versal_fpga: + $ref: /schemas/fpga/xlnx,versal-fpga.yaml# + description: Compatible of the FPGA device. + type: object + + zynqmp-aes: + $ref: /schemas/crypto/xlnx,zynqmp-aes.yaml# + description: The ZynqMP AES-GCM hardened cryptographic accelerator is + used to encrypt or decrypt the data with provided key and initialization + vector. + type: object + + clock-controller: + $ref: /schemas/clock/xlnx,versal-clk.yaml# + description: The clock controller is a hardware block of Xilinx versal + clock tree. It reads required input clock frequencies from the devicetree + and acts as clock provider for all clock consumers of PS clocks.list of + clock specifiers which are external input clocks to the given clock + controller. + type: object + +required: + - compatible + +additionalProperties: false + +examples: + - | + versal-firmware { + compatible = "xlnx,versal-firmware"; + method = "smc"; + + versal_fpga: versal_fpga { + compatible = "xlnx,versal-fpga"; + }; + + xlnx_aes: zynqmp-aes { + compatible = "xlnx,zynqmp-aes"; + }; + + versal_clk: clock-controller { + #clock-cells = <1>; + compatible = "xlnx,versal-clk"; + clocks = <&ref>, <&alt_ref>, <&pl_alt_ref>; + clock-names = "ref", "alt_ref", "pl_alt_ref"; + }; + }; + +... -- cgit v1.2.3 From 8c9b1301171f6690144d45a3e18ba676acbc34bc Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Sat, 26 Jun 2021 21:22:47 +0530 Subject: dt-bindings: firmware: Remove xlnx,zynqmp-firmware.txt file The funtionality of xlnx,zynqmp-firmware.txt is replaced with xlnx,zynqmp-firmware.yaml bindings so this patch removes the zynqmp-firmware.txt file Reviewed-by: Rob Herring Signed-off-by: Nava kishore Manne Link: https://lore.kernel.org/r/20210626155248.5004-5-nava.manne@xilinx.com Signed-off-by: Greg Kroah-Hartman --- .../firmware/xilinx/xlnx,zynqmp-firmware.txt | 44 ---------------------- 1 file changed, 44 deletions(-) delete mode 100644 Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt diff --git a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt b/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt deleted file mode 100644 index 18c3aea90df2..000000000000 --- a/Documentation/devicetree/bindings/firmware/xilinx/xlnx,zynqmp-firmware.txt +++ /dev/null @@ -1,44 +0,0 @@ ------------------------------------------------------------------ -Device Tree Bindings for the Xilinx Zynq MPSoC Firmware Interface ------------------------------------------------------------------ - -The zynqmp-firmware node describes the interface to platform firmware. -ZynqMP has an interface to communicate with secure firmware. Firmware -driver provides an interface to firmware APIs. Interface APIs can be -used by any driver to communicate to PMUFW(Platform Management Unit). -These requests include clock management, pin control, device control, -power management service, FPGA service and other platform management -services. - -Required properties: - - compatible: Must contain any of below: - "xlnx,zynqmp-firmware" for Zynq Ultrascale+ MPSoC - "xlnx,versal-firmware" for Versal - - method: The method of calling the PM-API firmware layer. - Permitted values are: - - "smc" : SMC #0, following the SMCCC - - "hvc" : HVC #0, following the SMCCC - -------- -Example -------- - -Zynq Ultrascale+ MPSoC ----------------------- -firmware { - zynqmp_firmware: zynqmp-firmware { - compatible = "xlnx,zynqmp-firmware"; - method = "smc"; - ... - }; -}; - -Versal ------- -firmware { - versal_firmware: versal-firmware { - compatible = "xlnx,versal-firmware"; - method = "smc"; - ... - }; -}; -- cgit v1.2.3 From 01c54e628932c655e4cd2c6ed0cc688ec6e6f96b Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Sat, 26 Jun 2021 21:22:48 +0530 Subject: fpga: versal-fpga: Add versal fpga manager driver Add support for Xilinx Versal FPGA manager. PDI source type can be DDR, OCM, QSPI flash etc.. But driver allocates memory always from DDR, Since driver supports only DDR source type. Reviewed-by: Moritz Fischer Signed-off-by: Appana Durga Kedareswara rao Signed-off-by: Nava kishore Manne Link: https://lore.kernel.org/r/20210626155248.5004-6-nava.manne@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/Kconfig | 9 +++++ drivers/fpga/Makefile | 1 + drivers/fpga/versal-fpga.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 drivers/fpga/versal-fpga.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 8cd454ee20c0..16793bfc2bb4 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -234,4 +234,13 @@ config FPGA_MGR_ZYNQMP_FPGA to configure the programmable logic(PL) through PS on ZynqMP SoC. +config FPGA_MGR_VERSAL_FPGA + tristate "Xilinx Versal FPGA" + depends on ARCH_ZYNQMP || COMPILE_TEST + help + Select this option to enable FPGA manager driver support for + Xilinx Versal SoC. This driver uses the firmware interface to + configure the programmable logic(PL). + + To compile this as a module, choose M here. endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 18dc9885883a..0bff783d1b61 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o +obj-$(CONFIG_FPGA_MGR_VERSAL_FPGA) += versal-fpga.o obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o diff --git a/drivers/fpga/versal-fpga.c b/drivers/fpga/versal-fpga.c new file mode 100644 index 000000000000..1bd312a31b23 --- /dev/null +++ b/drivers/fpga/versal-fpga.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019-2021 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int versal_fpga_ops_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t size) +{ + return 0; +} + +static int versal_fpga_ops_write(struct fpga_manager *mgr, + const char *buf, size_t size) +{ + dma_addr_t dma_addr = 0; + char *kbuf; + int ret; + + kbuf = dma_alloc_coherent(mgr->dev.parent, size, &dma_addr, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + memcpy(kbuf, buf, size); + ret = zynqmp_pm_load_pdi(PDI_SRC_DDR, dma_addr); + dma_free_coherent(mgr->dev.parent, size, kbuf, dma_addr); + + return ret; +} + +static int versal_fpga_ops_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + return 0; +} + +static enum fpga_mgr_states versal_fpga_ops_state(struct fpga_manager *mgr) +{ + return FPGA_MGR_STATE_UNKNOWN; +} + +static const struct fpga_manager_ops versal_fpga_ops = { + .state = versal_fpga_ops_state, + .write_init = versal_fpga_ops_write_init, + .write = versal_fpga_ops_write, + .write_complete = versal_fpga_ops_write_complete, +}; + +static int versal_fpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct fpga_manager *mgr; + int ret; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret < 0) { + dev_err(dev, "no usable DMA configuration\n"); + return ret; + } + + mgr = devm_fpga_mgr_create(dev, "Xilinx Versal FPGA Manager", + &versal_fpga_ops, NULL); + if (!mgr) + return -ENOMEM; + + return devm_fpga_mgr_register(dev, mgr); +} + +static const struct of_device_id versal_fpga_of_match[] = { + { .compatible = "xlnx,versal-fpga", }, + {}, +}; +MODULE_DEVICE_TABLE(of, versal_fpga_of_match); + +static struct platform_driver versal_fpga_driver = { + .probe = versal_fpga_probe, + .driver = { + .name = "versal_fpga_manager", + .of_match_table = of_match_ptr(versal_fpga_of_match), + }, +}; +module_platform_driver(versal_fpga_driver); + +MODULE_AUTHOR("Nava kishore Manne "); +MODULE_AUTHOR("Appana Durga Kedareswara rao "); +MODULE_DESCRIPTION("Xilinx Versal FPGA Manager"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From f83461e6581b12833ecf08690d21b04ed60de7c1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 15 Jul 2021 17:31:22 +0100 Subject: speakup: use C99 syntax for array initializers The older obsolete array initializer syntax is currently being used for some of the array elements. Fix this by using the preferred C99 array initializers syntax. Fixes: 5b5140bf5182 ("speakup: Separate out translations for bright colors names") Reviewed-by: Samuel Thibault Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210715163122.62220-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/speakup/i18n.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/accessibility/speakup/i18n.c b/drivers/accessibility/speakup/i18n.c index bc7b47d1876f..d62079b1661f 100644 --- a/drivers/accessibility/speakup/i18n.c +++ b/drivers/accessibility/speakup/i18n.c @@ -90,13 +90,13 @@ static char *speakup_default_msgs[MSG_LAST_INDEX] = { [MSG_COLOR_YELLOW] = "yellow", [MSG_COLOR_WHITE] = "white", [MSG_COLOR_GREY] = "grey", - [MSG_COLOR_BRIGHTBLUE] "bright blue", - [MSG_COLOR_BRIGHTGREEN] "bright green", - [MSG_COLOR_BRIGHTCYAN] "bright cyan", - [MSG_COLOR_BRIGHTRED] "bright red", - [MSG_COLOR_BRIGHTMAGENTA] "bright magenta", - [MSG_COLOR_BRIGHTYELLOW] "bright yellow", - [MSG_COLOR_BRIGHTWHITE] "bright white", + [MSG_COLOR_BRIGHTBLUE] = "bright blue", + [MSG_COLOR_BRIGHTGREEN] = "bright green", + [MSG_COLOR_BRIGHTCYAN] = "bright cyan", + [MSG_COLOR_BRIGHTRED] = "bright red", + [MSG_COLOR_BRIGHTMAGENTA] = "bright magenta", + [MSG_COLOR_BRIGHTYELLOW] = "bright yellow", + [MSG_COLOR_BRIGHTWHITE] = "bright white", /* Names of key states. */ [MSG_STATE_DOUBLE] = "double", -- cgit v1.2.3 From ec7b5eda8ae1a7a12cf1618ad7afb3509f593812 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Thu, 1 Jul 2021 00:42:48 +0200 Subject: speakup: replace sprintf() by scnprintf() Replace sprintf() by scnprintf() in order to avoid buffer overflows. Signed-off-by: Salah Triki Signed-off-by: Samuel Thibault Link: https://lore.kernel.org/r/20210630224248.2iq6o6krecx4cz5j@begin Signed-off-by: Greg Kroah-Hartman --- drivers/accessibility/speakup/speakup_soft.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/accessibility/speakup/speakup_soft.c b/drivers/accessibility/speakup/speakup_soft.c index c3f97c572fb6..19824e7006fe 100644 --- a/drivers/accessibility/speakup/speakup_soft.c +++ b/drivers/accessibility/speakup/speakup_soft.c @@ -153,18 +153,25 @@ static char *get_initstring(void) static char buf[40]; char *cp; struct var_t *var; + size_t len; + size_t n; memset(buf, 0, sizeof(buf)); cp = buf; + len = sizeof(buf); + var = synth_soft.vars; while (var->var_id != MAXVARS) { if (var->var_id != CAPS_START && var->var_id != CAPS_STOP && - var->var_id != PAUSE && var->var_id != DIRECT) - cp = cp + sprintf(cp, var->u.n.synth_fmt, - var->u.n.value); + var->var_id != PAUSE && var->var_id != DIRECT) { + n = scnprintf(cp, len, var->u.n.synth_fmt, + var->u.n.value); + cp = cp + n; + len = len - n; + } var++; } - cp = cp + sprintf(cp, "\n"); + cp = cp + scnprintf(cp, len, "\n"); return buf; } -- cgit v1.2.3 From fc470abf54b2bd6e539065e07905e767b443d719 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 15 Jul 2021 03:18:03 +0000 Subject: binderfs: add support for feature files Provide userspace with a mechanism to discover features supported by the binder driver to refrain from using any unsupported ones in the first place. Starting with "oneway_spam_detection" only new features are to be listed under binderfs and all previous ones are assumed to be supported. Assuming an instance of binderfs has been mounted at /dev/binderfs, binder feature files can be found under /dev/binderfs/features/. Usage example: $ mkdir /dev/binderfs $ mount -t binder binder /dev/binderfs $ cat /dev/binderfs/features/oneway_spam_detection 1 Acked-by: Christian Brauner Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20210715031805.1725878-1-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binderfs.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/drivers/android/binderfs.c b/drivers/android/binderfs.c index e80ba93c62a9..e3605cdd4335 100644 --- a/drivers/android/binderfs.c +++ b/drivers/android/binderfs.c @@ -58,6 +58,10 @@ enum binderfs_stats_mode { binderfs_stats_mode_global, }; +struct binder_features { + bool oneway_spam_detection; +}; + static const struct constant_table binderfs_param_stats[] = { { "global", binderfs_stats_mode_global }, {} @@ -69,6 +73,10 @@ static const struct fs_parameter_spec binderfs_fs_parameters[] = { {} }; +static struct binder_features binder_features = { + .oneway_spam_detection = true, +}; + static inline struct binderfs_info *BINDERFS_SB(const struct super_block *sb) { return sb->s_fs_info; @@ -583,6 +591,33 @@ out: return dentry; } +static int binder_features_show(struct seq_file *m, void *unused) +{ + bool *feature = m->private; + + seq_printf(m, "%d\n", *feature); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(binder_features); + +static int init_binder_features(struct super_block *sb) +{ + struct dentry *dentry, *dir; + + dir = binderfs_create_dir(sb->s_root, "features"); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + dentry = binderfs_create_file(dir, "oneway_spam_detection", + &binder_features_fops, + &binder_features.oneway_spam_detection); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + return 0; +} + static int init_binder_logs(struct super_block *sb) { struct dentry *binder_logs_root_dir, *dentry, *proc_log_dir; @@ -723,6 +758,10 @@ static int binderfs_fill_super(struct super_block *sb, struct fs_context *fc) name++; } + ret = init_binder_features(sb); + if (ret) + return ret; + if (info->mount_opts.stats_mode == binderfs_stats_mode_global) return init_binder_logs(sb); -- cgit v1.2.3 From 06e1721d2a265d1247093f5ad5ae2958ef10a604 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 15 Jul 2021 03:18:04 +0000 Subject: docs: binderfs: add section about feature files Document how binder feature files can be used to determine whether a feature is supported by the binder driver. "oneway_spam_detection" is used as an example as it is the first available feature file. Acked-by: Christian Brauner Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20210715031805.1725878-2-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- Documentation/admin-guide/binderfs.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Documentation/admin-guide/binderfs.rst b/Documentation/admin-guide/binderfs.rst index 199d84314a14..41a4db00df8d 100644 --- a/Documentation/admin-guide/binderfs.rst +++ b/Documentation/admin-guide/binderfs.rst @@ -72,3 +72,16 @@ that the `rm() `_ tool can be used to delete them. Note that the ``binder-control`` device cannot be deleted since this would make the binderfs instance unusable. The ``binder-control`` device will be deleted when the binderfs instance is unmounted and all references to it have been dropped. + +Binder features +--------------- + +Assuming an instance of binderfs has been mounted at ``/dev/binderfs``, the +features supported by the binder driver can be located under +``/dev/binderfs/features/``. The presence of individual files can be tested +to determine whether a particular feature is supported by the driver. + +Example:: + + cat /dev/binderfs/features/oneway_spam_detection + 1 -- cgit v1.2.3 From 07e913418ce4ba5eb620dd4668bf91ec94e11136 Mon Sep 17 00:00:00 2001 From: Carlos Llamas Date: Thu, 15 Jul 2021 03:18:05 +0000 Subject: selftests/binderfs: add test for feature files Verify that feature files are created successfully after mounting a binderfs instance. Note that only "oneway_spam_detection" feature is tested with this patch as it is currently the only feature listed. Acked-by: Christian Brauner Signed-off-by: Carlos Llamas Link: https://lore.kernel.org/r/20210715031805.1725878-3-cmllamas@google.com Signed-off-by: Greg Kroah-Hartman --- .../selftests/filesystems/binderfs/binderfs_test.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c index 477cbb042f5b..0315955ff0f4 100644 --- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c +++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c @@ -62,6 +62,9 @@ static int __do_binderfs_test(struct __test_metadata *_metadata) struct binder_version version = { 0 }; char binderfs_mntpt[] = P_tmpdir "/binderfs_XXXXXX", device_path[sizeof(P_tmpdir "/binderfs_XXXXXX/") + BINDERFS_MAX_NAME]; + static const char * const binder_features[] = { + "oneway_spam_detection", + }; change_mountns(_metadata); @@ -150,6 +153,20 @@ static int __do_binderfs_test(struct __test_metadata *_metadata) } /* success: binder-control device removal failed as expected */ + + for (int i = 0; i < ARRAY_SIZE(binder_features); i++) { + snprintf(device_path, sizeof(device_path), "%s/features/%s", + binderfs_mntpt, binder_features[i]); + fd = open(device_path, O_CLOEXEC | O_RDONLY); + EXPECT_GE(fd, 0) { + TH_LOG("%s - Failed to open binder feature: %s", + strerror(errno), binder_features[i]); + goto umount; + } + close(fd); + } + + /* success: binder feature files found */ result = 0; umount: -- cgit v1.2.3 From 03acb0c5ac46b1aa5f3015f1e01243aff9e08600 Mon Sep 17 00:00:00 2001 From: Xiyu Yang Date: Sat, 17 Jul 2021 18:17:22 +0800 Subject: misc: sgi-gru: Convert from atomic_t to refcount_t on gru_thread_state->ts_refcnt refcount_t type and corresponding API can protect refcounters from accidental underflow and overflow and further use-after-free situations. Acked-by: Dimitri Sivanich Signed-off-by: Xiyu Yang Signed-off-by: Xin Tan Link: https://lore.kernel.org/r/1626517043-42696-1-git-send-email-xiyuyang19@fudan.edu.cn Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-gru/grumain.c | 6 +++--- drivers/misc/sgi-gru/grutables.h | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 40ac59dd018c..9afda47efbf2 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -282,7 +282,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru, */ void gts_drop(struct gru_thread_state *gts) { - if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { + if (gts && refcount_dec_and_test(>s->ts_refcnt)) { if (gts->ts_gms) gru_drop_mmu_notifier(gts->ts_gms); kfree(gts); @@ -323,7 +323,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, STAT(gts_alloc); memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ - atomic_set(>s->ts_refcnt, 1); + refcount_set(>s->ts_refcnt, 1); mutex_init(>s->ts_ctxlock); gts->ts_cbr_au_count = cbr_au_count; gts->ts_dsr_au_count = dsr_au_count; @@ -888,7 +888,7 @@ again: gts->ts_gru = gru; gts->ts_blade = gru->gs_blade_id; gts->ts_ctxnum = gru_assign_context_number(gru); - atomic_inc(>s->ts_refcnt); + refcount_inc(>s->ts_refcnt); gru->gs_gts[gts->ts_ctxnum] = gts; spin_unlock(&gru->gs_lock); diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h index 5ce8f3081e96..e4c067c61251 100644 --- a/drivers/misc/sgi-gru/grutables.h +++ b/drivers/misc/sgi-gru/grutables.h @@ -129,6 +129,7 @@ * */ +#include #include #include #include @@ -358,7 +359,7 @@ struct gru_thread_state { enabled */ int ts_ctxnum; /* context number where the context is loaded */ - atomic_t ts_refcnt; /* reference count GTS */ + refcount_t ts_refcnt; /* reference count GTS */ unsigned char ts_dsr_au_count;/* Number of DSR resources required for contest */ unsigned char ts_cbr_au_count;/* Number of CBR resources -- cgit v1.2.3 From aa0a1ae020e2d24749e9f8085f12ca6d46899c94 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:11 +0300 Subject: bus: fsl-mc: fix arg in call to dprc_scan_objects() Second parameter of dprc_scan_objects() is a bool not a pointer so change from NULL to false. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-1-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 09c8ab5e0959..ffec838450f3 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -220,7 +220,7 @@ static int scan_fsl_mc_bus(struct device *dev, void *data) root_mc_dev = to_fsl_mc_device(dev); root_mc_bus = to_fsl_mc_bus(root_mc_dev); mutex_lock(&root_mc_bus->scan_mutex); - dprc_scan_objects(root_mc_dev, NULL); + dprc_scan_objects(root_mc_dev, false); mutex_unlock(&root_mc_bus->scan_mutex); exit: -- cgit v1.2.3 From f8cfa9bbab338b64229bffb93fdbb755be9d58d5 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:12 +0300 Subject: bus: fsl-mc: handle DMA config deferral in ACPI case ACPI DMA configure API may return a defer status code, so handle it. On top of this, move the MC firmware resume after the DMA setup is completed to avoid crashing due to DMA setup not being done yet or being deferred. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-2-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index ffec838450f3..ffd7a1ff957a 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1089,17 +1089,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) } if (mc->fsl_mc_regs) { - /* - * Some bootloaders pause the MC firmware before booting the - * kernel so that MC will not cause faults as soon as the - * SMMU probes due to the fact that there's no configuration - * in place for MC. - * At this point MC should have all its SMMU setup done so make - * sure it is resumed. - */ - writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), - mc->fsl_mc_regs + FSL_MC_GCR1); - if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) { mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR); /* @@ -1113,11 +1102,24 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) error = acpi_dma_configure_id(&pdev->dev, DEV_DMA_COHERENT, &mc_stream_id); + if (error == -EPROBE_DEFER) + return error; if (error) dev_warn(&pdev->dev, "failed to configure dma: %d.\n", error); } + + /* + * Some bootloaders pause the MC firmware before booting the + * kernel so that MC will not cause faults as soon as the + * SMMU probes due to the fact that there's no configuration + * in place for MC. + * At this point MC should have all its SMMU setup done so make + * sure it is resumed. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), + mc->fsl_mc_regs + FSL_MC_GCR1); } /* -- cgit v1.2.3 From c40cbad63ddcbf47debe350e736e37525a0c336c Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:13 +0300 Subject: bus: fsl-mc: fully resume the firmware The MC firmware has two execution units. Resume them both, as on some Layerscape SoCs not doing so breaks the firmware. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-3-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index ffd7a1ff957a..2341de6bce67 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -63,6 +63,7 @@ struct fsl_mc_addr_translation_range { #define FSL_MC_GCR1 0x0 #define GCR1_P1_STOP BIT(31) +#define GCR1_P2_STOP BIT(30) #define FSL_MC_FAPR 0x28 #define MC_FAPR_PL BIT(18) @@ -1118,7 +1119,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) * At this point MC should have all its SMMU setup done so make * sure it is resumed. */ - writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & (~GCR1_P1_STOP), + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) & + (~(GCR1_P1_STOP | GCR1_P2_STOP)), mc->fsl_mc_regs + FSL_MC_GCR1); } -- cgit v1.2.3 From 3ab520cfc772a63e037b5d433c3976c6426bf080 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:14 +0300 Subject: bus: fsl-mc: add .shutdown() op for the bus driver The fsl-mc bus driver is missing the .shutdown() callback, so add it. The implementation simply calls the .remove() callback. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-4-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 2341de6bce67..efff48b3efa5 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1206,6 +1206,11 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) return 0; } +static void fsl_mc_bus_shutdown(struct platform_device *pdev) +{ + fsl_mc_bus_remove(pdev); +} + static const struct of_device_id fsl_mc_bus_match_table[] = { {.compatible = "fsl,qoriq-mc",}, {}, @@ -1228,6 +1233,7 @@ static struct platform_driver fsl_mc_bus_driver = { }, .probe = fsl_mc_bus_probe, .remove = fsl_mc_bus_remove, + .shutdown = fsl_mc_bus_shutdown, }; static int __init fsl_mc_bus_driver_init(void) -- cgit v1.2.3 From 8c97a4fc1b34856812b6775f1f1d46b3bf59bc9d Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:15 +0300 Subject: bus: fsl-mc: pause the MC firmware before IOMMU setup Add a bus notifier to pause the MC firmware as soon as its device gets discovered. This is needed as the firmware is live thus, as soon as the SMMU gets probed and enabled, it will crash the firmware due to SMMU context faults. The firmware will be resumed at probe time, after the required IOMMU setup was completed. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-5-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 44 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index efff48b3efa5..41861ca5c8f1 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -896,6 +896,8 @@ error_cleanup_dev: } EXPORT_SYMBOL_GPL(fsl_mc_device_add); +static struct notifier_block fsl_mc_nb; + /** * fsl_mc_device_remove - Remove an fsl-mc device from being visible to * Linux @@ -1203,6 +1205,8 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) fsl_destroy_mc_io(mc->root_mc_bus_dev->mc_io); mc->root_mc_bus_dev->mc_io = NULL; + bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb); + return 0; } @@ -1236,6 +1240,44 @@ static struct platform_driver fsl_mc_bus_driver = { .shutdown = fsl_mc_bus_shutdown, }; +static int fsl_mc_bus_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct resource *res; + void __iomem *fsl_mc_regs; + + if (action != BUS_NOTIFY_ADD_DEVICE) + return 0; + + if (!of_match_device(fsl_mc_bus_match_table, dev) && + !acpi_match_device(fsl_mc_bus_acpi_match_table, dev)) + return 0; + + res = platform_get_resource(to_platform_device(dev), IORESOURCE_MEM, 1); + if (!res) + return 0; + + fsl_mc_regs = ioremap(res->start, resource_size(res)); + if (!fsl_mc_regs) + return 0; + + /* + * Make sure that the MC firmware is paused before the IOMMU setup for + * it is done or otherwise the firmware will crash right after the SMMU + * gets probed and enabled. + */ + writel(readl(fsl_mc_regs + FSL_MC_GCR1) | (GCR1_P1_STOP | GCR1_P2_STOP), + fsl_mc_regs + FSL_MC_GCR1); + iounmap(fsl_mc_regs); + + return 0; +} + +static struct notifier_block fsl_mc_nb = { + .notifier_call = fsl_mc_bus_notifier, +}; + static int __init fsl_mc_bus_driver_init(void) { int error; @@ -1260,7 +1302,7 @@ static int __init fsl_mc_bus_driver_init(void) if (error < 0) goto error_cleanup_dprc_driver; - return 0; + return bus_register_notifier(&platform_bus_type, &fsl_mc_nb); error_cleanup_dprc_driver: dprc_driver_exit(); -- cgit v1.2.3 From 39243fc1110caf1e76ea647059e061a021680dfd Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:16 +0300 Subject: bus: fsl-mc: pause the MC firmware when unloading Pause the MC firmware when unloading the driver so that it doesn't crash in certain scenarios, such as kexec. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-6-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 41861ca5c8f1..e5b4830cf3c5 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -1207,6 +1207,16 @@ static int fsl_mc_bus_remove(struct platform_device *pdev) bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb); + if (mc->fsl_mc_regs) { + /* + * Pause the MC firmware so that it doesn't crash in certain + * scenarios, such as kexec. + */ + writel(readl(mc->fsl_mc_regs + FSL_MC_GCR1) | + (GCR1_P1_STOP | GCR1_P2_STOP), + mc->fsl_mc_regs + FSL_MC_GCR1); + } + return 0; } -- cgit v1.2.3 From 8567494cebe5c208faa336a8316781d32d4e860f Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:17 +0300 Subject: bus: fsl-mc: rescan devices if endpoint not found If the endpoint of a device is not yet probed on the bus, force a rescan of the devices and retry to get a reference to the endpoint device. If the device is still not found then we assume it's in a different isolation context (container/DPRC) thus unavailable and return a permission error. Signed-off-by: Laurentiu Tudor Signed-off-by: Robert-Ionut Alexa Link: https://lore.kernel.org/r/20210715140718.8513-7-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index e5b4830cf3c5..31595017d207 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -950,10 +950,28 @@ struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev) * We know that the device has an endpoint because we verified by * interrogating the firmware. This is the case when the device was not * yet discovered by the fsl-mc bus, thus the lookup returned NULL. - * Differentiate this case by returning EPROBE_DEFER. + * Force a rescan of the devices in this container and retry the lookup. + */ + if (!endpoint) { + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); + + if (mutex_trylock(&mc_bus->scan_mutex)) { + err = dprc_scan_objects(mc_bus_dev, true); + mutex_unlock(&mc_bus->scan_mutex); + } + + if (err < 0) + return ERR_PTR(err); + } + + endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev); + /* + * This means that the endpoint might reside in a different isolation + * context (DPRC/container). Not much to do, so return a permssion + * error. */ if (!endpoint) - return ERR_PTR(-EPROBE_DEFER); + return ERR_PTR(-EPERM); return endpoint; } -- cgit v1.2.3 From 8990f96a012f42543005b07d9e482694192e9309 Mon Sep 17 00:00:00 2001 From: Laurentiu Tudor Date: Thu, 15 Jul 2021 17:07:18 +0300 Subject: bus: fsl-mc: fix mmio base address for child DPRCs Some versions of the MC firmware wrongly report 0 for register base address of the DPMCP associated with child DPRC objects thus rendering them unusable. This is particularly troublesome in ACPI boot scenarios where the legacy way of extracting this base address from the device tree does not apply. Given that DPMCPs share the same base address, workaround this by using the base address extracted from the root DPRC container. Signed-off-by: Laurentiu Tudor Link: https://lore.kernel.org/r/20210715140718.8513-8-laurentiu.tudor@nxp.com Signed-off-by: Greg Kroah-Hartman --- drivers/bus/fsl-mc/fsl-mc-bus.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 31595017d207..6273f782d0f2 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -69,6 +69,8 @@ struct fsl_mc_addr_translation_range { #define MC_FAPR_PL BIT(18) #define MC_FAPR_BMT BIT(17) +static phys_addr_t mc_portal_base_phys_addr; + /** * fsl_mc_bus_match - device to driver matching callback * @dev: the fsl-mc device to match against @@ -704,14 +706,30 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, * If base address is in the region_desc use it otherwise * revert to old mechanism */ - if (region_desc.base_address) + if (region_desc.base_address) { regions[i].start = region_desc.base_address + region_desc.base_offset; - else + } else { error = translate_mc_addr(mc_dev, mc_region_type, region_desc.base_offset, ®ions[i].start); + /* + * Some versions of the MC firmware wrongly report + * 0 for register base address of the DPMCP associated + * with child DPRC objects thus rendering them unusable. + * This is particularly troublesome in ACPI boot + * scenarios where the legacy way of extracting this + * base address from the device tree does not apply. + * Given that DPMCPs share the same base address, + * workaround this by using the base address extracted + * from the root DPRC container. + */ + if (is_fsl_mc_bus_dprc(mc_dev) && + regions[i].start == region_desc.base_offset) + regions[i].start += mc_portal_base_phys_addr; + } + if (error < 0) { dev_err(parent_dev, "Invalid MC offset: %#x (for %s.%d\'s region %d)\n", @@ -1150,6 +1168,8 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mc_portal_phys_addr = plat_res->start; mc_portal_size = resource_size(plat_res); + mc_portal_base_phys_addr = mc_portal_phys_addr & ~0x3ffffff; + error = fsl_create_mc_io(&pdev->dev, mc_portal_phys_addr, mc_portal_size, NULL, FSL_MC_IO_ATOMIC_CONTEXT_PORTAL, &mc_io); -- cgit v1.2.3 From 28b6a003bcdfa1fc4603b9185b247ecca7af9bef Mon Sep 17 00:00:00 2001 From: Eric Auger Date: Tue, 29 Jun 2021 09:22:14 +0200 Subject: misc/pvpanic-pci: Allow automatic loading The virtual machine monitor (QEMU) exposes the pvpanic-pci device to the guest. On guest side the module exists but currently isn't loaded automatically. So the driver fails to be probed and does not its job of handling guest panic events. Instead of requiring manual modprobe, let's include a device database using the MODULE_DEVICE_TABLE macro and let the module auto-load when the guest gets exposed with such a pvpanic-pci device. Signed-off-by: Eric Auger Link: https://lore.kernel.org/r/20210629072214.901004-1-eric.auger@redhat.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic-pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c index a43c401017ae..741116b3d995 100644 --- a/drivers/misc/pvpanic/pvpanic-pci.c +++ b/drivers/misc/pvpanic/pvpanic-pci.c @@ -108,4 +108,6 @@ static struct pci_driver pvpanic_pci_driver = { }, }; +MODULE_DEVICE_TABLE(pci, pvpanic_pci_id_tbl); + module_pci_driver(pvpanic_pci_driver); -- cgit v1.2.3 From ddb1381018766202894b167c700e0852f52a9b9d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 11 Jul 2021 15:31:46 -0700 Subject: MOST: cdev: rename 'mod_init' & 'mod_exit' functions to be module-specific Rename module_init & module_exit functions that are named "mod_init" and "mod_exit" so that they are unique in both the System.map file and in initcall_debug output instead of showing up as almost anonymous "mod_init". This is helpful for debugging and in determining how long certain module_init calls take to execute. Signed-off-by: Randy Dunlap Acked-by: Christian Gromm Link: https://lore.kernel.org/r/20210711223148.5250-5-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/most/most_cdev.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/most/most_cdev.c b/drivers/most/most_cdev.c index 8908b9363a96..3722f9abd7b9 100644 --- a/drivers/most/most_cdev.c +++ b/drivers/most/most_cdev.c @@ -486,7 +486,7 @@ static struct cdev_component comp = { }, }; -static int __init mod_init(void) +static int __init most_cdev_init(void) { int err; @@ -518,7 +518,7 @@ dest_ida: return err; } -static void __exit mod_exit(void) +static void __exit most_cdev_exit(void) { struct comp_channel *c, *tmp; @@ -534,8 +534,8 @@ static void __exit mod_exit(void) class_destroy(comp.class); } -module_init(mod_init); -module_exit(mod_exit); +module_init(most_cdev_init); +module_exit(most_cdev_exit); MODULE_AUTHOR("Christian Gromm "); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("character device component for mostcore"); -- cgit v1.2.3 From 36cdc20b79ef8841d38217ea8ba837a7dbfbe852 Mon Sep 17 00:00:00 2001 From: Wan Jiabing Date: Mon, 28 Jun 2021 20:35:12 +0800 Subject: lkdtm: remove duplicated include of init.h Fix following checkincludes.pl warning: ./drivers/misc/lkdtm/core.c 26 #include 29 #include Acked-by: Kees Cook Signed-off-by: Wan Jiabing Link: https://lore.kernel.org/r/20210628123512.38090-1-wanjiabing@vivo.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 9dda87c6b54a..c9a0ad6d5d72 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -26,7 +26,6 @@ #include #include #include -#include #define DEFAULT_COUNT 10 -- cgit v1.2.3 From d1d26f40f71c6eabeb2083e2a18d2e55e9a71336 Mon Sep 17 00:00:00 2001 From: Salah Triki Date: Fri, 2 Jul 2021 14:31:14 +0100 Subject: dio: return -ENOMEM when kzalloc() fails Return -ENOMEM when kzalloc() fails in order to inform the caller of the failure. Signed-off-by: Salah Triki Link: https://lore.kernel.org/r/20210702133114.GA314157@pc Signed-off-by: Greg Kroah-Hartman --- drivers/dio/dio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c index 193b40e7aec0..4c06c93c93d3 100644 --- a/drivers/dio/dio.c +++ b/drivers/dio/dio.c @@ -219,7 +219,7 @@ static int __init dio_init(void) /* Found a board, allocate it an entry in the list */ dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL); if (!dev) - return 0; + return -ENOMEM; dev->bus = &dio_bus; dev->dev.parent = &dio_bus.dev; -- cgit v1.2.3 From 74a03c20bc8809a41d66ea614e55358064adbd7d Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Tue, 6 Jul 2021 17:43:10 +0200 Subject: misc: pci_endpoint_test: Ensure relationship between miscdev and PCI Set the parent pointer of the misc device to ensure a relationship between PCI and misc dev. That way it is possible to see in /sys/class/misc/ which pci_endpoint_test instance serves what PCI device. Signed-off-by: Richard Weinberger Link: https://lore.kernel.org/r/20210706154310.26773-1-richard@nod.at Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pci_endpoint_test.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c index 1b2868ca4f2a..d1137a95ad02 100644 --- a/drivers/misc/pci_endpoint_test.c +++ b/drivers/misc/pci_endpoint_test.c @@ -862,6 +862,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev, err = -ENOMEM; goto err_release_irq; } + misc_device->parent = &pdev->dev; misc_device->fops = &pci_endpoint_test_fops, err = misc_register(misc_device); -- cgit v1.2.3 From 03b1292d1c0ea195e025e667555d74db7da82026 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 7 Jul 2021 16:06:00 -0500 Subject: scripts/spdxcheck-test.sh: Drop python2 Since commit d0259c42abff ("spdxcheck.py: Use Python 3"), spdxcheck.py explicitly expects to run as python3 script, there is no further point in attempting to test with python2. Cc: Bert Vermeulen Signed-off-by: Nishanth Menon Link: https://lore.kernel.org/r/20210707210600.7266-1-nm@ti.com Signed-off-by: Greg Kroah-Hartman --- scripts/spdxcheck-test.sh | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/scripts/spdxcheck-test.sh b/scripts/spdxcheck-test.sh index cfea6a0d1cc0..cb76324756bd 100644 --- a/scripts/spdxcheck-test.sh +++ b/scripts/spdxcheck-test.sh @@ -1,12 +1,10 @@ #!/bin/sh -for PYTHON in python2 python3; do - # run check on a text and a binary file - for FILE in Makefile Documentation/logo.gif; do - $PYTHON scripts/spdxcheck.py $FILE - $PYTHON scripts/spdxcheck.py - < $FILE - done - - # run check on complete tree to catch any other issues - $PYTHON scripts/spdxcheck.py > /dev/null +# run check on a text and a binary file +for FILE in Makefile Documentation/logo.gif; do + python3 scripts/spdxcheck.py $FILE + python3 scripts/spdxcheck.py - < $FILE done + +# run check on complete tree to catch any other issues +python3 scripts/spdxcheck.py > /dev/null -- cgit v1.2.3 From 758f74674bcb82e1ed1a0b5a56980f295183b546 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 10 May 2021 12:26:25 +0200 Subject: docs: driver-api: fpga: avoid using UTF-8 chars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While UTF-8 characters can be used at the Linux documentation, the best is to use them only when ASCII doesn't offer a good replacement. So, replace the occurences of the following UTF-8 characters: - U+2014 ('—'): EM DASH Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Moritz Fischer --- Documentation/driver-api/fpga/fpga-bridge.rst | 10 +++++----- Documentation/driver-api/fpga/fpga-mgr.rst | 12 ++++++------ Documentation/driver-api/fpga/fpga-programming.rst | 8 ++++---- Documentation/driver-api/fpga/fpga-region.rst | 20 ++++++++++---------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/Documentation/driver-api/fpga/fpga-bridge.rst b/Documentation/driver-api/fpga/fpga-bridge.rst index 198aadafd3e7..8d650b4e2ce6 100644 --- a/Documentation/driver-api/fpga/fpga-bridge.rst +++ b/Documentation/driver-api/fpga/fpga-bridge.rst @@ -4,11 +4,11 @@ FPGA Bridge API to implement a new FPGA bridge ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -* struct fpga_bridge — The FPGA Bridge structure -* struct fpga_bridge_ops — Low level Bridge driver ops -* devm_fpga_bridge_create() — Allocate and init a bridge struct -* fpga_bridge_register() — Register a bridge -* fpga_bridge_unregister() — Unregister a bridge +* struct fpga_bridge - The FPGA Bridge structure +* struct fpga_bridge_ops - Low level Bridge driver ops +* devm_fpga_bridge_create() - Allocate and init a bridge struct +* fpga_bridge_register() - Register a bridge +* fpga_bridge_unregister() - Unregister a bridge .. kernel-doc:: include/linux/fpga/fpga-bridge.h :functions: fpga_bridge diff --git a/Documentation/driver-api/fpga/fpga-mgr.rst b/Documentation/driver-api/fpga/fpga-mgr.rst index 917ee22db429..4d926b452cb3 100644 --- a/Documentation/driver-api/fpga/fpga-mgr.rst +++ b/Documentation/driver-api/fpga/fpga-mgr.rst @@ -101,12 +101,12 @@ in state. API for implementing a new FPGA Manager driver ---------------------------------------------- -* ``fpga_mgr_states`` — Values for :c:expr:`fpga_manager->state`. -* struct fpga_manager — the FPGA manager struct -* struct fpga_manager_ops — Low level FPGA manager driver ops -* devm_fpga_mgr_create() — Allocate and init a manager struct -* fpga_mgr_register() — Register an FPGA manager -* fpga_mgr_unregister() — Unregister an FPGA manager +* ``fpga_mgr_states`` - Values for :c:expr:`fpga_manager->state`. +* struct fpga_manager - the FPGA manager struct +* struct fpga_manager_ops - Low level FPGA manager driver ops +* devm_fpga_mgr_create() - Allocate and init a manager struct +* fpga_mgr_register() - Register an FPGA manager +* fpga_mgr_unregister() - Unregister an FPGA manager .. kernel-doc:: include/linux/fpga/fpga-mgr.h :functions: fpga_mgr_states diff --git a/Documentation/driver-api/fpga/fpga-programming.rst b/Documentation/driver-api/fpga/fpga-programming.rst index 002392dab04f..fb4da4240e96 100644 --- a/Documentation/driver-api/fpga/fpga-programming.rst +++ b/Documentation/driver-api/fpga/fpga-programming.rst @@ -84,10 +84,10 @@ will generate that list. Here's some sample code of what to do next:: API for programming an FPGA --------------------------- -* fpga_region_program_fpga() — Program an FPGA -* fpga_image_info() — Specifies what FPGA image to program -* fpga_image_info_alloc() — Allocate an FPGA image info struct -* fpga_image_info_free() — Free an FPGA image info struct +* fpga_region_program_fpga() - Program an FPGA +* fpga_image_info() - Specifies what FPGA image to program +* fpga_image_info_alloc() - Allocate an FPGA image info struct +* fpga_image_info_free() - Free an FPGA image info struct .. kernel-doc:: drivers/fpga/fpga-region.c :functions: fpga_region_program_fpga diff --git a/Documentation/driver-api/fpga/fpga-region.rst b/Documentation/driver-api/fpga/fpga-region.rst index 363a8171ab0a..2636a27c11b2 100644 --- a/Documentation/driver-api/fpga/fpga-region.rst +++ b/Documentation/driver-api/fpga/fpga-region.rst @@ -45,19 +45,19 @@ An example of usage can be seen in the probe function of [#f2]_. API to add a new FPGA region ---------------------------- -* struct fpga_region — The FPGA region struct -* devm_fpga_region_create() — Allocate and init a region struct -* fpga_region_register() — Register an FPGA region -* fpga_region_unregister() — Unregister an FPGA region +* struct fpga_region - The FPGA region struct +* devm_fpga_region_create() - Allocate and init a region struct +* fpga_region_register() - Register an FPGA region +* fpga_region_unregister() - Unregister an FPGA region The FPGA region's probe function will need to get a reference to the FPGA Manager it will be using to do the programming. This usually would happen during the region's probe function. -* fpga_mgr_get() — Get a reference to an FPGA manager, raise ref count -* of_fpga_mgr_get() — Get a reference to an FPGA manager, raise ref count, +* fpga_mgr_get() - Get a reference to an FPGA manager, raise ref count +* of_fpga_mgr_get() - Get a reference to an FPGA manager, raise ref count, given a device node. -* fpga_mgr_put() — Put an FPGA manager +* fpga_mgr_put() - Put an FPGA manager The FPGA region will need to specify which bridges to control while programming the FPGA. The region driver can build a list of bridges during probe time @@ -66,11 +66,11 @@ the list of bridges to program just before programming (:c:expr:`fpga_region->get_bridges`). The FPGA bridge framework supplies the following APIs to handle building or tearing down that list. -* fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a +* fpga_bridge_get_to_list() - Get a ref of an FPGA bridge, add it to a list -* of_fpga_bridge_get_to_list() — Get a ref of an FPGA bridge, add it to a +* of_fpga_bridge_get_to_list() - Get a ref of an FPGA bridge, add it to a list, given a device node -* fpga_bridges_put() — Given a list of bridges, put them +* fpga_bridges_put() - Given a list of bridges, put them .. kernel-doc:: include/linux/fpga/fpga-region.h :functions: fpga_region -- cgit v1.2.3 From 580e3137318edb39d2c6efa5dad51e3fbd7e2536 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Wed, 19 May 2021 09:30:56 -0700 Subject: fpga: fix spelling mistakes Run the fpga subsystem through aspell. Signed-off-by: Tom Rix Reviewed-by: Fernando Pacheco Signed-off-by: Moritz Fischer --- Documentation/fpga/dfl.rst | 4 ++-- drivers/fpga/altera-cvp.c | 2 +- drivers/fpga/dfl-fme-pr.c | 2 +- drivers/fpga/dfl-n3000-nios.c | 2 +- drivers/fpga/dfl.h | 2 +- drivers/fpga/fpga-bridge.c | 4 ++-- drivers/fpga/zynq-fpga.c | 6 +++--- include/linux/fpga/fpga-mgr.h | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Documentation/fpga/dfl.rst b/Documentation/fpga/dfl.rst index 75df90d1e54c..ef9eec71f6f3 100644 --- a/Documentation/fpga/dfl.rst +++ b/Documentation/fpga/dfl.rst @@ -10,7 +10,7 @@ Authors: - Xu Yilun The Device Feature List (DFL) FPGA framework (and drivers according to -this framework) hides the very details of low layer hardwares and provides +this framework) hides the very details of low layer hardware and provides unified interfaces to userspace. Applications could use these interfaces to configure, enumerate, open and access FPGA accelerators on platforms which implement the DFL in the device memory. Besides this, the DFL framework @@ -205,7 +205,7 @@ given Device Feature Lists and create platform devices for feature devices also abstracts operations for the private features and exposes common ops to feature device drivers. -The FPGA DFL Device could be different hardwares, e.g. PCIe device, platform +The FPGA DFL Device could be different hardware, e.g. PCIe device, platform device and etc. Its driver module is always loaded first once the device is created by the system. This driver plays an infrastructural role in the driver architecture. It locates the DFLs in the device memory, handles them diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 4e0edb60bfba..ccf4546eff29 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -346,7 +346,7 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, } if (val & VSE_CVP_STATUS_CFG_RDY) { - dev_warn(&mgr->dev, "CvP already started, teardown first\n"); + dev_warn(&mgr->dev, "CvP already started, tear down first\n"); ret = altera_cvp_teardown(mgr, info); if (ret) return ret; diff --git a/drivers/fpga/dfl-fme-pr.c b/drivers/fpga/dfl-fme-pr.c index 1194c0e850e0..d61ce9a18879 100644 --- a/drivers/fpga/dfl-fme-pr.c +++ b/drivers/fpga/dfl-fme-pr.c @@ -148,7 +148,7 @@ static int fme_pr(struct platform_device *pdev, unsigned long arg) /* * it allows userspace to reset the PR region's logic by disabling and - * reenabling the bridge to clear things out between accleration runs. + * reenabling the bridge to clear things out between acceleration runs. * so no need to hold the bridges after partial reconfiguration. */ if (region->get_bridges) diff --git a/drivers/fpga/dfl-n3000-nios.c b/drivers/fpga/dfl-n3000-nios.c index 7a95366f6516..9ddf1d1d392f 100644 --- a/drivers/fpga/dfl-n3000-nios.c +++ b/drivers/fpga/dfl-n3000-nios.c @@ -461,7 +461,7 @@ static int n3000_nios_poll_stat_timeout(void __iomem *base, u64 *v) * We don't use the time based timeout here for performance. * * The regbus read/write is on the critical path of Intel PAC N3000 - * image programing. The time based timeout checking will add too much + * image programming. The time based timeout checking will add too much * overhead on it. Usually the state changes in 1 or 2 loops on the * test server, and we set 10000 times loop here for safety. */ diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 2b82c96ba56c..dac9c3d45e6c 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -232,7 +232,7 @@ struct dfl_feature_irq_ctx { * @id: sub feature id. * @resource_index: each sub feature has one mmio resource for its registers. * this index is used to find its mmio resource from the - * feature dev (platform device)'s reources. + * feature dev (platform device)'s resources. * @ioaddr: mapped mmio resource address. * @irq_ctx: interrupt context list. * @nr_irqs: number of interrupt contexts. diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index 2bfb2ff86930..b09f68f8e1b0 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -230,7 +230,7 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put); * * Get an exclusive reference to the bridge and and it to the list. * - * Return 0 for success, error code from of_fpga_bridge_get() othewise. + * Return 0 for success, error code from of_fpga_bridge_get() otherwise. */ int of_fpga_bridge_get_to_list(struct device_node *np, struct fpga_image_info *info, @@ -260,7 +260,7 @@ EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); * * Get an exclusive reference to the bridge and and it to the list. * - * Return 0 for success, error code from fpga_bridge_get() othewise. + * Return 0 for success, error code from fpga_bridge_get() otherwise. */ int fpga_bridge_get_to_list(struct device *dev, struct fpga_image_info *info, diff --git a/drivers/fpga/zynq-fpga.c b/drivers/fpga/zynq-fpga.c index 07fa8d9ec675..9b75bd4f93d8 100644 --- a/drivers/fpga/zynq-fpga.c +++ b/drivers/fpga/zynq-fpga.c @@ -192,7 +192,7 @@ static void zynq_step_dma(struct zynq_fpga_priv *priv) /* Once the first transfer is queued we can turn on the ISR, future * calls to zynq_step_dma will happen from the ISR context. The - * dma_lock spinlock guarentees this handover is done coherently, the + * dma_lock spinlock guarantees this handover is done coherently, the * ISR enable is put at the end to avoid another CPU spinning in the * ISR on this lock. */ @@ -267,7 +267,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, ctrl = zynq_fpga_read(priv, CTRL_OFFSET); if (!(ctrl & CTRL_SEC_EN_MASK)) { dev_err(&mgr->dev, - "System not secure, can't use crypted bitstreams\n"); + "System not secure, can't use encrypted bitstreams\n"); err = -EINVAL; goto out_err; } @@ -344,7 +344,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, /* set configuration register with following options: * - enable PCAP interface - * - set throughput for maximum speed (if bistream not crypted) + * - set throughput for maximum speed (if bistream not encrypted) * - set CPU in user mode */ ctrl = zynq_fpga_read(priv, CTRL_OFFSET); diff --git a/include/linux/fpga/fpga-mgr.h b/include/linux/fpga/fpga-mgr.h index ec2cd8bfceb0..474c1f506307 100644 --- a/include/linux/fpga/fpga-mgr.h +++ b/include/linux/fpga/fpga-mgr.h @@ -110,7 +110,7 @@ struct fpga_image_info { * @initial_header_size: Maximum number of bytes that should be passed into write_init * @state: returns an enum value of the FPGA's state * @status: returns status of the FPGA, including reconfiguration error code - * @write_init: prepare the FPGA to receive confuration data + * @write_init: prepare the FPGA to receive configuration data * @write: write count bytes of configuration data to the FPGA * @write_sg: write the scatter list of configuration data to the FPGA * @write_complete: set FPGA to operating state after writing is done -- cgit v1.2.3 From 0a05cdf18b1a92c29dddaa82b04b9e885a0126b7 Mon Sep 17 00:00:00 2001 From: Navin Sankar Velliangiri Date: Fri, 28 May 2021 20:35:57 +0530 Subject: fpga: fpga-bridge: removed repeated word Removed repeated word and. Reported by checkpatch. Signed-off-by: Navin Sankar Velliangiri Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-bridge.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c index b09f68f8e1b0..798f55670646 100644 --- a/drivers/fpga/fpga-bridge.c +++ b/drivers/fpga/fpga-bridge.c @@ -228,7 +228,7 @@ EXPORT_SYMBOL_GPL(fpga_bridges_put); * @info: fpga image specific information * @bridge_list: list of FPGA bridges * - * Get an exclusive reference to the bridge and and it to the list. + * Get an exclusive reference to the bridge and it to the list. * * Return 0 for success, error code from of_fpga_bridge_get() otherwise. */ @@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(of_fpga_bridge_get_to_list); * @info: fpga image specific information * @bridge_list: list of FPGA bridges * - * Get an exclusive reference to the bridge and and it to the list. + * Get an exclusive reference to the bridge and it to the list. * * Return 0 for success, error code from fpga_bridge_get() otherwise. */ -- cgit v1.2.3 From 789a39ad39bc7ff24fe16f80326a6e38f047f10b Mon Sep 17 00:00:00 2001 From: Mike Tipton Date: Mon, 21 Jun 2021 14:42:41 -0700 Subject: interconnect: qcom: icc-rpmh: Consolidate probe functions The current probe/remove functions are implemented separately for each target, but they are almost identical. Replace them with common functions that can be used across all rpmh targets. Signed-off-by: Mike Tipton Reviewed-by: Matthias Kaehlcke Link: https://lore.kernel.org/r/20210621214241.13521-1-mdtipton@codeaurora.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/icc-rpmh.c | 93 +++++++++++++++++++++++++++++++++ drivers/interconnect/qcom/icc-rpmh.h | 2 + drivers/interconnect/qcom/sc7180.c | 96 +--------------------------------- drivers/interconnect/qcom/sc7280.c | 96 +--------------------------------- drivers/interconnect/qcom/sdm845.c | 99 +----------------------------------- drivers/interconnect/qcom/sdx55.c | 96 +--------------------------------- drivers/interconnect/qcom/sm8150.c | 96 +--------------------------------- drivers/interconnect/qcom/sm8250.c | 96 +--------------------------------- drivers/interconnect/qcom/sm8350.c | 97 +---------------------------------- 9 files changed, 109 insertions(+), 662 deletions(-) diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index bf01d09dba6c..e1de186ecc78 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "bcm-voter.h" @@ -184,4 +185,96 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev) } EXPORT_SYMBOL_GPL(qcom_icc_bcm_init); +int qcom_icc_rpmh_probe(struct platform_device *pdev) +{ + const struct qcom_icc_desc *desc; + struct device *dev = &pdev->dev; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes, *qn; + struct qcom_icc_provider *qp; + struct icc_node *node; + size_t num_nodes, i, j; + int ret; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider = &qp->provider; + provider->dev = dev; + provider->set = qcom_icc_set; + provider->pre_aggregate = qcom_icc_pre_aggregate; + provider->aggregate = qcom_icc_aggregate; + provider->xlate_extended = qcom_icc_xlate_extended; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + qp->dev = dev; + qp->bcms = desc->bcms; + qp->num_bcms = desc->num_bcms; + + qp->voter = of_bcm_voter_get(qp->dev, NULL); + if (IS_ERR(qp->voter)) + return PTR_ERR(qp->voter); + + ret = icc_provider_add(provider); + if (ret) + return ret; + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_init(qp->bcms[i], dev); + + for (i = 0; i < num_nodes; i++) { + qn = qnodes[i]; + if (!qn) + continue; + + node = icc_node_create(qn->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qn->name; + node->data = qn; + icc_node_add(node, provider); + + for (j = 0; j < qn->num_links; j++) + icc_link_create(node, qn->links[j]); + + data->nodes[i] = node; + } + + data->num_nodes = num_nodes; + platform_set_drvdata(pdev, qp); + + return 0; +err: + icc_nodes_remove(provider); + icc_provider_del(provider); + return ret; +} +EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe); + +int qcom_icc_rpmh_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + return icc_provider_del(&qp->provider); +} +EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove); + MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/icc-rpmh.h b/drivers/interconnect/qcom/icc-rpmh.h index e5f61ab989e7..4bfc060529ba 100644 --- a/drivers/interconnect/qcom/icc-rpmh.h +++ b/drivers/interconnect/qcom/icc-rpmh.h @@ -134,5 +134,7 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst); struct icc_node_data *qcom_icc_xlate_extended(struct of_phandle_args *spec, void *data); int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev); void qcom_icc_pre_aggregate(struct icc_node *node); +int qcom_icc_rpmh_probe(struct platform_device *pdev); +int qcom_icc_rpmh_remove(struct platform_device *pdev); #endif diff --git a/drivers/interconnect/qcom/sc7180.c b/drivers/interconnect/qcom/sc7180.c index 8d9044ed18ab..12d59c36df53 100644 --- a/drivers/interconnect/qcom/sc7180.c +++ b/drivers/interconnect/qcom/sc7180.c @@ -504,98 +504,6 @@ static struct qcom_icc_desc sc7180_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate_extended = qcom_icc_xlate_extended; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sc7180-aggre1-noc", .data = &sc7180_aggre1_noc}, @@ -628,8 +536,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7180", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sc7280.c b/drivers/interconnect/qcom/sc7280.c index 8d1b55c3705c..f8b34f6cbb0d 100644 --- a/drivers/interconnect/qcom/sc7280.c +++ b/drivers/interconnect/qcom/sc7280.c @@ -1802,98 +1802,6 @@ static struct qcom_icc_desc sc7280_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate_extended = qcom_icc_xlate_extended; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sc7280-aggre1-noc", .data = &sc7280_aggre1_noc}, @@ -1924,8 +1832,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sc7280", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdm845.c b/drivers/interconnect/qcom/sdm845.c index 366870150cbd..d2195079c228 100644 --- a/drivers/interconnect/qcom/sdm845.c +++ b/drivers/interconnect/qcom/sdm845.c @@ -440,101 +440,6 @@ static const struct qcom_icc_desc sdm845_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kzalloc(&pdev->dev, struct_size(data, nodes, num_nodes), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate_extended = qcom_icc_xlate_extended; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) { - dev_err(&pdev->dev, "bcm_voter err:%ld\n", PTR_ERR(qp->voter)); - return PTR_ERR(qp->voter); - } - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sdm845-aggre1-noc", .data = &sdm845_aggre1_noc}, @@ -557,8 +462,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdm845", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sdx55.c b/drivers/interconnect/qcom/sdx55.c index a5a122ee3d21..03d604f84cc5 100644 --- a/drivers/interconnect/qcom/sdx55.c +++ b/drivers/interconnect/qcom/sdx55.c @@ -235,98 +235,6 @@ static const struct qcom_icc_desc sdx55_ipa_virt = { .num_bcms = ARRAY_SIZE(ipa_virt_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate = of_icc_xlate_onecell; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sdx55-mc-virt", .data = &sdx55_mc_virt}, @@ -341,8 +249,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sdx55", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8150.c b/drivers/interconnect/qcom/sm8150.c index c76b2c7f9b10..2a85f53802b5 100644 --- a/drivers/interconnect/qcom/sm8150.c +++ b/drivers/interconnect/qcom/sm8150.c @@ -502,98 +502,6 @@ static struct qcom_icc_desc sm8150_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate = of_icc_xlate_onecell; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sm8150-aggre1-noc", .data = &sm8150_aggre1_noc}, @@ -622,8 +530,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8150", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8250.c b/drivers/interconnect/qcom/sm8250.c index cc558fec74e3..8dfb5dea562a 100644 --- a/drivers/interconnect/qcom/sm8250.c +++ b/drivers/interconnect/qcom/sm8250.c @@ -518,98 +518,6 @@ static struct qcom_icc_desc sm8250_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate = of_icc_xlate_onecell; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return 0; -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sm8250-aggre1-noc", .data = &sm8250_aggre1_noc}, @@ -638,8 +546,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8250", .of_match_table = qnoc_of_match, diff --git a/drivers/interconnect/qcom/sm8350.c b/drivers/interconnect/qcom/sm8350.c index 579b6ce8e046..3e26a2175b28 100644 --- a/drivers/interconnect/qcom/sm8350.c +++ b/drivers/interconnect/qcom/sm8350.c @@ -510,99 +510,6 @@ static struct qcom_icc_desc sm8350_system_noc = { .num_bcms = ARRAY_SIZE(system_noc_bcms), }; -static int qnoc_probe(struct platform_device *pdev) -{ - const struct qcom_icc_desc *desc; - struct icc_onecell_data *data; - struct icc_provider *provider; - struct qcom_icc_node **qnodes; - struct qcom_icc_provider *qp; - struct icc_node *node; - size_t num_nodes, i; - int ret; - - desc = of_device_get_match_data(&pdev->dev); - if (!desc) - return -EINVAL; - - qnodes = desc->nodes; - num_nodes = desc->num_nodes; - - qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); - if (!qp) - return -ENOMEM; - - data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); - if (!data) - return -ENOMEM; - - provider = &qp->provider; - provider->dev = &pdev->dev; - provider->set = qcom_icc_set; - provider->pre_aggregate = qcom_icc_pre_aggregate; - provider->aggregate = qcom_icc_aggregate; - provider->xlate = of_icc_xlate_onecell; - INIT_LIST_HEAD(&provider->nodes); - provider->data = data; - - qp->dev = &pdev->dev; - qp->bcms = desc->bcms; - qp->num_bcms = desc->num_bcms; - - qp->voter = of_bcm_voter_get(qp->dev, NULL); - if (IS_ERR(qp->voter)) - return PTR_ERR(qp->voter); - - ret = icc_provider_add(provider); - if (ret) { - dev_err(&pdev->dev, "error adding interconnect provider\n"); - return ret; - } - - for (i = 0; i < qp->num_bcms; i++) - qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); - - for (i = 0; i < num_nodes; i++) { - size_t j; - - if (!qnodes[i]) - continue; - - node = icc_node_create(qnodes[i]->id); - if (IS_ERR(node)) { - ret = PTR_ERR(node); - goto err; - } - - node->name = qnodes[i]->name; - node->data = qnodes[i]; - icc_node_add(node, provider); - - for (j = 0; j < qnodes[i]->num_links; j++) - icc_link_create(node, qnodes[i]->links[j]); - - data->nodes[i] = node; - } - data->num_nodes = num_nodes; - - platform_set_drvdata(pdev, qp); - - return ret; - -err: - icc_nodes_remove(provider); - icc_provider_del(provider); - return ret; -} - -static int qnoc_remove(struct platform_device *pdev) -{ - struct qcom_icc_provider *qp = platform_get_drvdata(pdev); - - icc_nodes_remove(&qp->provider); - return icc_provider_del(&qp->provider); -} - static const struct of_device_id qnoc_of_match[] = { { .compatible = "qcom,sm8350-aggre1-noc", .data = &sm8350_aggre1_noc}, { .compatible = "qcom,sm8350-aggre2-noc", .data = &sm8350_aggre2_noc}, @@ -619,8 +526,8 @@ static const struct of_device_id qnoc_of_match[] = { MODULE_DEVICE_TABLE(of, qnoc_of_match); static struct platform_driver qnoc_driver = { - .probe = qnoc_probe, - .remove = qnoc_remove, + .probe = qcom_icc_rpmh_probe, + .remove = qcom_icc_rpmh_remove, .driver = { .name = "qnoc-sm8350", .of_match_table = qnoc_of_match, -- cgit v1.2.3 From 9cc969675dea496b6689f576ddd4d8fd172705c5 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Fri, 25 Jun 2021 16:49:03 -0700 Subject: interconnect: Sanity check that node isn't already on list Broken interconnect providers might add the same node multiple times or in multiple providers, which causes strange errors as the provider's node list is later traversed. Detect that a node already has an associated provider, complain and reject the addition of the node, to aid the developer. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210625234903.1324755-1-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c index 8a1e70e00876..fcb5d8eefb51 100644 --- a/drivers/interconnect/core.c +++ b/drivers/interconnect/core.c @@ -959,6 +959,9 @@ EXPORT_SYMBOL_GPL(icc_link_destroy); */ void icc_node_add(struct icc_node *node, struct icc_provider *provider) { + if (WARN_ON(node->provider)) + return; + mutex_lock(&icc_lock); node->provider = provider; -- cgit v1.2.3 From bfccd9a71a08627bcccd40277967516ddd9d5db2 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 21 Jul 2021 09:30:29 -0700 Subject: phy: qcom-qmp: Fix sc8180x PCIe definition A copy paste error was snuck into the patch going upstream that made the SC8180x PCIe PHY use the SM8250 serdes table, but while this works there's some differences in the tables (and the SC8180x was left dangling). So correct the SC8180x definition to use the SC8180x serdes table. Fixes: f839f14e24f2 ("phy: qcom-qmp: Add sc8180x PCIe support") Reported-by: kernel test robot Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210721163029.2813497-1-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 655bdef26143..2195f8ac393b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -3510,7 +3510,7 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { .type = PHY_TYPE_PCIE, .nlanes = 1, - .serdes_tbl = sm8250_qmp_pcie_serdes_tbl, + .serdes_tbl = sc8180x_qmp_pcie_serdes_tbl, .serdes_tbl_num = ARRAY_SIZE(sm8250_qmp_pcie_serdes_tbl), .tx_tbl = sc8180x_qmp_pcie_tx_tbl, .tx_tbl_num = ARRAY_SIZE(sc8180x_qmp_pcie_tx_tbl), -- cgit v1.2.3 From c1302e8ce517ed9c417aa4eb19776df4efbbebf4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 21 Jul 2021 17:25:42 +0200 Subject: phy: tegra: xusb: mark PM functions as __maybe_unused When these are not referenced, gcc prints a harmless warning: drivers/phy/tegra/xusb.c:1286:12: error: 'tegra_xusb_padctl_resume_noirq' defined but not used [-Werror=unused-function] 1286 | static int tegra_xusb_padctl_resume_noirq(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ drivers/phy/tegra/xusb.c:1276:12: error: 'tegra_xusb_padctl_suspend_noirq' defined but not used [-Werror=unused-function] 1276 | static int tegra_xusb_padctl_suspend_noirq(struct device *dev) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Fixes: c545a9056712 ("phy: tegra: xusb: Add sleepwalk and suspend/resume") Signed-off-by: Arnd Bergmann Link: https://lore.kernel.org/r/20210721152550.2976003-1-arnd@kernel.org Signed-off-by: Vinod Koul --- drivers/phy/tegra/xusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 0aadac678191..963de5913e50 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c @@ -1273,7 +1273,7 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) return err; } -static int tegra_xusb_padctl_suspend_noirq(struct device *dev) +static __maybe_unused int tegra_xusb_padctl_suspend_noirq(struct device *dev) { struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev); @@ -1283,7 +1283,7 @@ static int tegra_xusb_padctl_suspend_noirq(struct device *dev) return 0; } -static int tegra_xusb_padctl_resume_noirq(struct device *dev) +static __maybe_unused int tegra_xusb_padctl_resume_noirq(struct device *dev) { struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev); -- cgit v1.2.3 From 433b308403aa2cd9213e954c566c4df25399570e Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 09:30:27 +0800 Subject: soundwire: dmi-quirks: add ull suffix for SoundWire _ADR values Sparse throws the following type of warnings: drivers/soundwire/dmi-quirks.c:25:17: error: constant 0x000010025D070100 is so big it is long Let's add the 'ull' suffix to make this go away and find real issues. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Paul Olaru Reviewed-by: Guennadi Liakhovetski Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714013027.17022-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/dmi-quirks.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 5db0a2443a1d..1ac16687e315 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -22,12 +22,12 @@ struct adr_remap { */ static const struct adr_remap hp_spectre_360[] = { { - 0x000010025D070100, - 0x000020025D071100 + 0x000010025D070100ull, + 0x000020025D071100ull }, { - 0x000110025d070100, - 0x000120025D130800 + 0x000110025d070100ull, + 0x000120025D130800ull }, {} }; @@ -39,18 +39,18 @@ static const struct adr_remap hp_spectre_360[] = { static const struct adr_remap dell_sku_0A3E[] = { /* rt715 on link0 */ { - 0x00020025d071100, - 0x00021025d071500 + 0x00020025d071100ull, + 0x00021025d071500ull }, /* rt711 on link1 */ { - 0x000120025d130800, - 0x000120025d071100, + 0x000120025d130800ull, + 0x000120025d071100ull, }, /* rt1308 on link2 */ { - 0x000220025d071500, - 0x000220025d130800 + 0x000220025d071500ull, + 0x000220025d130800ull }, {} }; -- cgit v1.2.3 From 9f9bc7d50437f11fecf5935ab91f44284e747222 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 09:42:09 +0800 Subject: soundwire: bus: filter out more -EDATA errors on clock stop We've added quite a few filters to avoid throwing errors if a Device does not respond to commands during the clock stop sequences, but we missed one. This will lead to an isolated message [ 6115.294412] soundwire sdw-master-1: SDW_SCP_STAT bread failed:-61 The callers already filter this error code, so there's no point in keeping it at the lower level. Since this is a recoverable error, make this dev_err() conditional and only log cases with Command Failed. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Guennadi Liakhovetski Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714014209.17357-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 3e6d4addac2f..278a4fbdb88d 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -896,7 +896,8 @@ static int sdw_bus_wait_for_clk_prep_deprep(struct sdw_bus *bus, u16 dev_num) do { val = sdw_bread_no_pm(bus, dev_num, SDW_SCP_STAT); if (val < 0) { - dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val); + if (val != -ENODATA) + dev_err(bus->dev, "SDW_SCP_STAT bread failed:%d\n", val); return val; } val &= SDW_SCP_STAT_CLK_STP_NF; -- cgit v1.2.3 From 00d3c2b3f0a2cb26ef27f015015b43c8a195c10f Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 14 Jul 2021 09:55:55 +0800 Subject: soundwire: cadence: Remove ret variable from sdw_cdns_irq() The ret is not used in the interrupt handler, it is just returned without any condition or change. We can return the IRQ_HANDLED directly. Signed-off-by: Peter Ujfalusi Reviewed-by: Guennadi Liakhovetski Reviewed-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714015555.17685-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 25950422b085..9a9b6110e763 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -822,7 +822,6 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) { struct sdw_cdns *cdns = dev_id; u32 int_status; - int ret = IRQ_HANDLED; /* Check if the link is up */ if (!cdns->link_up) @@ -900,7 +899,7 @@ irqreturn_t sdw_cdns_irq(int irq, void *dev_id) } cdns_writel(cdns, CDNS_MCP_INTSTAT, int_status); - return ret; + return IRQ_HANDLED; } EXPORT_SYMBOL(sdw_cdns_irq); -- cgit v1.2.3 From 899a750986bc4e62d554d4a5dd237c0ab25b698a Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 14 Jul 2021 11:36:09 +0800 Subject: soundwire: bus: update Slave status in sdw_clear_slave_status Call to sdw_update_slave_status() needs to be added to sdw_clear_slave_ status() to ensure Slaves are informed of the new status via update_ status() callback. This will enable codec drivers to reset their internal states and make sure the register settings are properly restored on pm_runtime or system resume BugLink: https://github.com/thesofproject/linux/issues/2908 BugLink: https://github.com/thesofproject/linux/issues/2637 Signed-off-by: Bard Liao Reviewed-by: Guennadi Liakhovetski Link: https://lore.kernel.org/r/20210714033609.11963-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index 278a4fbdb88d..b3ed0123ed27 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -1854,6 +1854,7 @@ void sdw_clear_slave_status(struct sdw_bus *bus, u32 request) if (slave->status != SDW_SLAVE_UNATTACHED) { sdw_modify_slave_status(slave, SDW_SLAVE_UNATTACHED); slave->first_interrupt_done = false; + sdw_update_slave_status(slave, SDW_SLAVE_UNATTACHED); } /* keep track of request, used in pm_runtime resume */ -- cgit v1.2.3 From caa15c8dcb00f9dfe9f304e6e0955c5b29cf2499 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Mon, 19 Jul 2021 18:32:47 -0500 Subject: soundwire: dmi-quirks: add quirk for Intel 'Bishop County' NUC M15 The same quirk is used for LAPBC510 and LAPBC710 skews who use the same audio design. These devices have the same BIOS issues inherited from the Intel reference, add the same _ADR remap previously used on HP devices. BugLink: https://github.com/thesofproject/linux/issues/3049 Signed-off-by: Pierre-Louis Bossart Reviewed-by: Bard Liao Reviewed-by: Kai Vehmanen Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20210719233248.557923-2-pierre-louis.bossart@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/dmi-quirks.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/soundwire/dmi-quirks.c b/drivers/soundwire/dmi-quirks.c index 1ac16687e315..0ca2a3e3a02e 100644 --- a/drivers/soundwire/dmi-quirks.c +++ b/drivers/soundwire/dmi-quirks.c @@ -16,11 +16,11 @@ struct adr_remap { }; /* - * HP Spectre 360 Convertible devices do not expose the correct _ADR - * in the DSDT. + * Some TigerLake devices based on an initial Intel BIOS do not expose + * the correct _ADR in the DSDT. * Remap the bad _ADR values to the ones reported by hardware */ -static const struct adr_remap hp_spectre_360[] = { +static const struct adr_remap intel_tgl_bios[] = { { 0x000010025D070100ull, 0x000020025D071100ull @@ -61,7 +61,15 @@ static const struct dmi_system_id adr_remap_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Convertible"), }, - .driver_data = (void *)hp_spectre_360, + .driver_data = (void *)intel_tgl_bios, + }, + { + /* quirk used for NUC15 'Bishop County' LAPBC510 and LAPBC710 skews */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"), + DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), + }, + .driver_data = (void *)intel_tgl_bios, }, { .matches = { -- cgit v1.2.3 From 82fb70b87f210ef4e7e7fb2443ac16aaab40c3e2 Mon Sep 17 00:00:00 2001 From: Martin Hundebøll Date: Fri, 25 Jun 2021 09:42:09 +0200 Subject: fpga: dfl: pci: add device IDs for Silicom N501x PAC cards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds the approved PCI Express Device IDs for the Silicom PAC N5010 and N5011 cards (aka. Silicom Lightning Creek cards). The N5010 features an FPGA that manages/interfaces four QSFP ports, and allows on-board custom packet processing/filtering/routing, based on logic loaded with user-provided FPGA bitstreams. The N5011 cards adds a PCIe switch that exposes, in addition to the FPGA itself, two Intel E810 (aka Columbiaville) ethernet controllers. With this, packets can be forwarded from the FPGA to the host for further processing. Signed-off-by: Martin Hundebøll Acked-by: Wu Hao Signed-off-by: Moritz Fischer --- drivers/fpga/dfl-pci.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/fpga/dfl-pci.c b/drivers/fpga/dfl-pci.c index b44523ea8c91..4d68719e608f 100644 --- a/drivers/fpga/dfl-pci.c +++ b/drivers/fpga/dfl-pci.c @@ -74,6 +74,9 @@ static void cci_pci_free_irq(struct pci_dev *pcidev) #define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4 #define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30 #define PCIE_DEVICE_ID_INTEL_PAC_D5005 0x0B2B +#define PCIE_DEVICE_ID_SILICOM_PAC_N5010 0x1000 +#define PCIE_DEVICE_ID_SILICOM_PAC_N5011 0x1001 + /* VF Device */ #define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF #define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1 @@ -90,6 +93,8 @@ static struct pci_device_id cci_pcie_id_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005),}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_D5005_VF),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5010),}, + {PCI_DEVICE(PCI_VENDOR_ID_SILICOM_DENMARK, PCIE_DEVICE_ID_SILICOM_PAC_N5011),}, {0,} }; MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl); -- cgit v1.2.3 From e3fd0cfb852b9d201973665e2287cce43dd92c77 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 1 Jul 2021 20:54:01 -0700 Subject: fpga: altera-freeze-bridge: Address warning about unused variable warning: unused variable 'altera_freeze_br_of_match' [-Wunused-const-variable] static const struct of_device_id altera_freeze_br_of_match[] = { Fixes: ca24a648f535 ("fpga: add altera freeze bridge support") Cc: Tom Rix Reported-by: kernel test robot Signed-off-by: Moritz Fischer --- drivers/fpga/altera-freeze-bridge.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/fpga/altera-freeze-bridge.c b/drivers/fpga/altera-freeze-bridge.c index dd58c4aea92e..7d22a44d652e 100644 --- a/drivers/fpga/altera-freeze-bridge.c +++ b/drivers/fpga/altera-freeze-bridge.c @@ -198,11 +198,13 @@ static const struct fpga_bridge_ops altera_freeze_br_br_ops = { .enable_show = altera_freeze_br_enable_show, }; +#ifdef CONFIG_OF static const struct of_device_id altera_freeze_br_of_match[] = { { .compatible = "altr,freeze-bridge-controller", }, {}, }; MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match); +#endif static int altera_freeze_br_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 1aa3fc699c11a6458d49837545b295361250a765 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 1 Jul 2021 20:54:02 -0700 Subject: fpga: xiilnx-spi: Address warning about unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit warning: ‘xlnx_spi_of_match’ defined but not used [-Wunused-const-variable] static const struct of_device_id xlnx_spi_of_match[] = { Fixes: 061c97d13f1a ("fpga manager: Add Xilinx slave serial SPI driver") Cc: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-spi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/fpga/xilinx-spi.c b/drivers/fpga/xilinx-spi.c index fee4d0abf6bf..b6bcf1d9233d 100644 --- a/drivers/fpga/xilinx-spi.c +++ b/drivers/fpga/xilinx-spi.c @@ -256,11 +256,13 @@ static int xilinx_spi_probe(struct spi_device *spi) return devm_fpga_mgr_register(&spi->dev, mgr); } +#ifdef CONFIG_OF static const struct of_device_id xlnx_spi_of_match[] = { { .compatible = "xlnx,fpga-slave-serial", }, {} }; MODULE_DEVICE_TABLE(of, xlnx_spi_of_match); +#endif static struct spi_driver xilinx_slave_spi_driver = { .driver = { -- cgit v1.2.3 From 56ddc787706c7413da63fb6640361285f1bb1d55 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 1 Jul 2021 20:54:03 -0700 Subject: fpga: xilinx-pr-decoupler: Address warning about unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit warning: ‘xlnx_pr_decoupler_of_match’ defined but not used [-Wunused-const-variable=] static const struct of_device_id xlnx_pr_decoupler_of_match[] = { Fixes: 7e961c12be42 ("fpga: Add support for Xilinx LogiCORE PR Decoupler") Cc: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/xilinx-pr-decoupler.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/fpga/xilinx-pr-decoupler.c b/drivers/fpga/xilinx-pr-decoupler.c index ea2bde6e5bc4..e986ed47c4ed 100644 --- a/drivers/fpga/xilinx-pr-decoupler.c +++ b/drivers/fpga/xilinx-pr-decoupler.c @@ -81,6 +81,7 @@ static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { .enable_show = xlnx_pr_decoupler_enable_show, }; +#ifdef CONFIG_OF static const struct xlnx_config_data decoupler_config = { .name = "Xilinx PR Decoupler", }; @@ -99,6 +100,7 @@ static const struct of_device_id xlnx_pr_decoupler_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); +#endif static int xlnx_pr_decoupler_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 6f125e87184ea5f8ad677c2cc4a9c9c6e717554b Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 1 Jul 2021 20:54:04 -0700 Subject: fpga: zynqmp-fpga: Address warning about unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit warning: ‘zynqmp_fpga_of_match’ defined but not used [-Wunused-const-variable=] static const struct of_device_id zynqmp_fpga_of_match[] = { Fixes: c09f7471127e ("fpga manager: Adding FPGA Manager support for Xilinx zynqmp") Cc: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/zynqmp-fpga.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c index 125743c9797f..b3240f75f0c7 100644 --- a/drivers/fpga/zynqmp-fpga.c +++ b/drivers/fpga/zynqmp-fpga.c @@ -110,12 +110,13 @@ static int zynqmp_fpga_probe(struct platform_device *pdev) return devm_fpga_mgr_register(dev, mgr); } +#ifdef CONFIG_OF static const struct of_device_id zynqmp_fpga_of_match[] = { { .compatible = "xlnx,zynqmp-pcap-fpga", }, {}, }; - MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match); +#endif static struct platform_driver zynqmp_fpga_driver = { .probe = zynqmp_fpga_probe, -- cgit v1.2.3 From 2e8438b754abcf13f2306237bd0bfe6e7dcb379a Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:42 -0700 Subject: fpga: fpga-mgr: wrap the write_init() op An FPGA manager should not be required to provide a write_init() op if there is nothing for it do. So add a wrapper and move the op checking. Default to success. [mdf@kernel.org: Reworded first line] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index ecb4c3c795fa..c047de8a059b 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,15 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +static inline int fpga_mgr_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t count) +{ + if (mgr->mops->write_init) + return mgr->mops->write_init(mgr, info, buf, count); + return 0; +} + /** * fpga_image_info_alloc - Allocate an FPGA image info struct * @dev: owning device @@ -83,9 +92,9 @@ static int fpga_mgr_write_init_buf(struct fpga_manager *mgr, mgr->state = FPGA_MGR_STATE_WRITE_INIT; if (!mgr->mops->initial_header_size) - ret = mgr->mops->write_init(mgr, info, NULL, 0); + ret = fpga_mgr_write_init(mgr, info, NULL, 0); else - ret = mgr->mops->write_init( + ret = fpga_mgr_write_init( mgr, info, buf, min(mgr->mops->initial_header_size, count)); if (ret) { @@ -569,7 +578,7 @@ struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name, int id, ret; if (!mops || !mops->write_complete || !mops->state || - !mops->write_init || (!mops->write && !mops->write_sg) || + (!mops->write && !mops->write_sg) || (mops->write && mops->write_sg)) { dev_err(parent, "Attempt to register without fpga_manager_ops\n"); return NULL; -- cgit v1.2.3 From 72d935020ea81c0092c23b580352fe1310505c28 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:43 -0700 Subject: fpga: fpga-mgr: make write_complete() op optional An FPGA manager should not be required to provide a write_complete function if there is nothing. Move the op check to the existing wrapper. Default to success and remove noop function. [mdf@kernel.org: Reworded message] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 45 +++++++++++++++++++++++---------------------- drivers/fpga/zynqmp-fpga.c | 7 ------- 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index c047de8a059b..05a69ab3ecb9 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,28 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +/* + * After all the FPGA image has been written, do the device specific steps to + * finish and set the FPGA into operating mode. + */ +static inline int fpga_mgr_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + int ret = 0; + + mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; + if (mgr->mops->write_complete) + ret = mgr->mops->write_complete(mgr, info); + if (ret) { + dev_err(&mgr->dev, "Error after writing image data to FPGA\n"); + mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; + return ret; + } + mgr->state = FPGA_MGR_STATE_OPERATING; + + return 0; +} + static inline int fpga_mgr_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count) @@ -146,27 +168,6 @@ static int fpga_mgr_write_init_sg(struct fpga_manager *mgr, return ret; } -/* - * After all the FPGA image has been written, do the device specific steps to - * finish and set the FPGA into operating mode. - */ -static int fpga_mgr_write_complete(struct fpga_manager *mgr, - struct fpga_image_info *info) -{ - int ret; - - mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE; - ret = mgr->mops->write_complete(mgr, info); - if (ret) { - dev_err(&mgr->dev, "Error after writing image data to FPGA\n"); - mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR; - return ret; - } - mgr->state = FPGA_MGR_STATE_OPERATING; - - return 0; -} - /** * fpga_mgr_buf_load_sg - load fpga from image in buffer from a scatter list * @mgr: fpga manager @@ -577,7 +578,7 @@ struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name, struct fpga_manager *mgr; int id, ret; - if (!mops || !mops->write_complete || !mops->state || + if (!mops || !mops->state || (!mops->write && !mops->write_sg) || (mops->write && mops->write_sg)) { dev_err(parent, "Attempt to register without fpga_manager_ops\n"); diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c index b3240f75f0c7..7d3d5650c322 100644 --- a/drivers/fpga/zynqmp-fpga.c +++ b/drivers/fpga/zynqmp-fpga.c @@ -66,12 +66,6 @@ static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, return ret; } -static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr, - struct fpga_image_info *info) -{ - return 0; -} - static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr) { u32 status = 0; @@ -87,7 +81,6 @@ static const struct fpga_manager_ops zynqmp_fpga_ops = { .state = zynqmp_fpga_ops_state, .write_init = zynqmp_fpga_ops_write_init, .write = zynqmp_fpga_ops_write, - .write_complete = zynqmp_fpga_ops_write_complete, }; static int zynqmp_fpga_probe(struct platform_device *pdev) -- cgit v1.2.3 From 8ebab40fd8f1683140890a77fadf571db98686b8 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:44 -0700 Subject: fpga: fpga-mgr: wrap the write() op An FPGA manager should not be required to provide a write function. Move the op check to the wrapper. Default to -EOPNOTSUP so its users will fail gracefully. [mdf@kernel.org: Reworded message] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 05a69ab3ecb9..8d5536d74808 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,13 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +static inline int fpga_mgr_write(struct fpga_manager *mgr, const char *buf, size_t count) +{ + if (mgr->mops->write) + return mgr->mops->write(mgr, buf, count); + return -EOPNOTSUPP; +} + /* * After all the FPGA image has been written, do the device specific steps to * finish and set the FPGA into operating mode. @@ -204,7 +211,7 @@ static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); while (sg_miter_next(&miter)) { - ret = mgr->mops->write(mgr, miter.addr, miter.length); + ret = fpga_mgr_write(mgr, miter.addr, miter.length); if (ret) break; } @@ -234,7 +241,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr, * Write the FPGA image to the FPGA. */ mgr->state = FPGA_MGR_STATE_WRITE; - ret = mgr->mops->write(mgr, buf, count); + ret = fpga_mgr_write(mgr, buf, count); if (ret) { dev_err(&mgr->dev, "Error while writing image data to FPGA\n"); mgr->state = FPGA_MGR_STATE_WRITE_ERR; @@ -578,9 +585,7 @@ struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name, struct fpga_manager *mgr; int id, ret; - if (!mops || !mops->state || - (!mops->write && !mops->write_sg) || - (mops->write && mops->write_sg)) { + if (!mops || !mops->state) { dev_err(parent, "Attempt to register without fpga_manager_ops\n"); return NULL; } -- cgit v1.2.3 From 6f9922711359d2092fb91036193dfed0d1bdf8b8 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:45 -0700 Subject: fpga: fpga-mgr: wrap the status() op An FPGA manager is not required to provide a status() op. Add a wrapper consistent with the other op wrappers. Move the op check to the wrapper. Default to 0, no errors to report. [mdf@kernel.org: Reworded first line] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 8d5536d74808..43518b6eed21 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,13 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +static inline u64 fpga_mgr_status(struct fpga_manager *mgr) +{ + if (mgr->mops->status) + return mgr->mops->status(mgr); + return 0; +} + static inline int fpga_mgr_write(struct fpga_manager *mgr, const char *buf, size_t count) { if (mgr->mops->write) @@ -434,10 +441,7 @@ static ssize_t status_show(struct device *dev, u64 status; int len = 0; - if (!mgr->mops->status) - return -ENOENT; - - status = mgr->mops->status(mgr); + status = fpga_mgr_status(mgr); if (status & FPGA_MGR_STATUS_OPERATION_ERR) len += sprintf(buf + len, "reconfig operation error\n"); -- cgit v1.2.3 From b02a40713db95ebd8f72151b0fea8080d9f74c27 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:46 -0700 Subject: fpga: fpga-mgr: wrap the state() op An FPGA manager should not be required to provide a state() op. Add a wrapper consistent with the other op wrappers. Move op check to wrapper. Default to FPGA_MGR_STATE_UNKNOWN, what noop state() ops use. Remove unneeded noop state() ops [mdf@kernel.org: Reworded first line] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/dfl-fme-mgr.c | 6 ------ drivers/fpga/fpga-mgr.c | 11 +++++++++-- drivers/fpga/stratix10-soc.c | 6 ------ drivers/fpga/ts73xx-fpga.c | 6 ------ 4 files changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/fpga/dfl-fme-mgr.c b/drivers/fpga/dfl-fme-mgr.c index d5861d13b306..313420405d5e 100644 --- a/drivers/fpga/dfl-fme-mgr.c +++ b/drivers/fpga/dfl-fme-mgr.c @@ -252,11 +252,6 @@ static int fme_mgr_write_complete(struct fpga_manager *mgr, return 0; } -static enum fpga_mgr_states fme_mgr_state(struct fpga_manager *mgr) -{ - return FPGA_MGR_STATE_UNKNOWN; -} - static u64 fme_mgr_status(struct fpga_manager *mgr) { struct fme_mgr_priv *priv = mgr->priv; @@ -268,7 +263,6 @@ static const struct fpga_manager_ops fme_mgr_ops = { .write_init = fme_mgr_write_init, .write = fme_mgr_write, .write_complete = fme_mgr_write_complete, - .state = fme_mgr_state, .status = fme_mgr_status, }; diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 43518b6eed21..b3380ad341d2 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,13 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +static inline enum fpga_mgr_states fpga_mgr_state(struct fpga_manager *mgr) +{ + if (mgr->mops->state) + return mgr->mops->state(mgr); + return FPGA_MGR_STATE_UNKNOWN; +} + static inline u64 fpga_mgr_status(struct fpga_manager *mgr) { if (mgr->mops->status) @@ -589,7 +596,7 @@ struct fpga_manager *fpga_mgr_create(struct device *parent, const char *name, struct fpga_manager *mgr; int id, ret; - if (!mops || !mops->state) { + if (!mops) { dev_err(parent, "Attempt to register without fpga_manager_ops\n"); return NULL; } @@ -707,7 +714,7 @@ int fpga_mgr_register(struct fpga_manager *mgr) * from device. FPGA may be in reset mode or may have been programmed * by bootloader or EEPROM. */ - mgr->state = mgr->mops->state(mgr); + mgr->state = fpga_mgr_state(mgr); ret = device_add(&mgr->dev); if (ret) diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c index a2cea500f7cc..047fd7f23706 100644 --- a/drivers/fpga/stratix10-soc.c +++ b/drivers/fpga/stratix10-soc.c @@ -388,13 +388,7 @@ static int s10_ops_write_complete(struct fpga_manager *mgr, return ret; } -static enum fpga_mgr_states s10_ops_state(struct fpga_manager *mgr) -{ - return FPGA_MGR_STATE_UNKNOWN; -} - static const struct fpga_manager_ops s10_ops = { - .state = s10_ops_state, .write_init = s10_ops_write_init, .write = s10_ops_write, .write_complete = s10_ops_write_complete, diff --git a/drivers/fpga/ts73xx-fpga.c b/drivers/fpga/ts73xx-fpga.c index 101f016c6ed8..167abb0b08d4 100644 --- a/drivers/fpga/ts73xx-fpga.c +++ b/drivers/fpga/ts73xx-fpga.c @@ -32,11 +32,6 @@ struct ts73xx_fpga_priv { struct device *dev; }; -static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr) -{ - return FPGA_MGR_STATE_UNKNOWN; -} - static int ts73xx_fpga_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count) @@ -98,7 +93,6 @@ static int ts73xx_fpga_write_complete(struct fpga_manager *mgr, } static const struct fpga_manager_ops ts73xx_fpga_ops = { - .state = ts73xx_fpga_state, .write_init = ts73xx_fpga_write_init, .write = ts73xx_fpga_write, .write_complete = ts73xx_fpga_write_complete, -- cgit v1.2.3 From 6489d3b00398f02457eea566d4a99698c68cc89f Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:47 -0700 Subject: fpga: fpga-mgr: wrap the fpga_remove() op An FPGA manager is not required to provide a fpga_remove() op. Add a wrapper consistent with the other op wrappers. Move op check to wrapper. [mdf@kernel.org: Reworded first line] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index b3380ad341d2..077c0f9edbe4 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -25,6 +25,12 @@ struct fpga_mgr_devres { struct fpga_manager *mgr; }; +static inline void fpga_mgr_fpga_remove(struct fpga_manager *mgr) +{ + if (mgr->mops->fpga_remove) + mgr->mops->fpga_remove(mgr); +} + static inline enum fpga_mgr_states fpga_mgr_state(struct fpga_manager *mgr) { if (mgr->mops->state) @@ -745,8 +751,7 @@ void fpga_mgr_unregister(struct fpga_manager *mgr) * If the low level driver provides a method for putting fpga into * a desired state upon unregister, do it. */ - if (mgr->mops->fpga_remove) - mgr->mops->fpga_remove(mgr); + fpga_mgr_fpga_remove(mgr); device_unregister(&mgr->dev); } -- cgit v1.2.3 From 630211a17055bafd21fb83ae8c0002b2e214ebb2 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Fri, 25 Jun 2021 12:51:48 -0700 Subject: fpga: fpga-mgr: wrap the write_sg() op An FPGA manager should not be required to provide a write_sg function. Move the op check to the wrapper. Default to -EOPNOTSUP so its users will fail gracefully. [mdf@kernel.org: Reworded first line] Signed-off-by: Tom Rix Signed-off-by: Moritz Fischer --- drivers/fpga/fpga-mgr.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 077c0f9edbe4..aa30889e2320 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -83,6 +83,14 @@ static inline int fpga_mgr_write_init(struct fpga_manager *mgr, return 0; } +static inline int fpga_mgr_write_sg(struct fpga_manager *mgr, + struct sg_table *sgt) +{ + if (mgr->mops->write_sg) + return mgr->mops->write_sg(mgr, sgt); + return -EOPNOTSUPP; +} + /** * fpga_image_info_alloc - Allocate an FPGA image info struct * @dev: owning device @@ -225,7 +233,7 @@ static int fpga_mgr_buf_load_sg(struct fpga_manager *mgr, /* Write the FPGA image to the FPGA. */ mgr->state = FPGA_MGR_STATE_WRITE; if (mgr->mops->write_sg) { - ret = mgr->mops->write_sg(mgr, sgt); + ret = fpga_mgr_write_sg(mgr, sgt); } else { struct sg_mapping_iter miter; -- cgit v1.2.3 From 9bb3a9dddbf1ca6e062464f790a6a18052d63a4a Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Sun, 25 Jul 2021 20:08:06 -0700 Subject: fpga: versal-fpga: Remove empty functions Since the core framework now wraps the functions, ensuring drives only have to implement functions that do something, drop the now no longer required callbacks for state and write_complete. Signed-off-by: Moritz Fischer Link: https://lore.kernel.org/r/20210726030806.714809-1-mdf@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/fpga/versal-fpga.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/fpga/versal-fpga.c b/drivers/fpga/versal-fpga.c index 1bd312a31b23..5b0dda304bd2 100644 --- a/drivers/fpga/versal-fpga.c +++ b/drivers/fpga/versal-fpga.c @@ -37,22 +37,9 @@ static int versal_fpga_ops_write(struct fpga_manager *mgr, return ret; } -static int versal_fpga_ops_write_complete(struct fpga_manager *mgr, - struct fpga_image_info *info) -{ - return 0; -} - -static enum fpga_mgr_states versal_fpga_ops_state(struct fpga_manager *mgr) -{ - return FPGA_MGR_STATE_UNKNOWN; -} - static const struct fpga_manager_ops versal_fpga_ops = { - .state = versal_fpga_ops_state, .write_init = versal_fpga_ops_write_init, .write = versal_fpga_ops_write, - .write_complete = versal_fpga_ops_write_complete, }; static int versal_fpga_probe(struct platform_device *pdev) -- cgit v1.2.3 From 0912ef4855e8e463a8d724efd6bee08e9b5d3f1e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 29 Jul 2021 12:28:03 +0200 Subject: mei: constify passed buffers and structures Buffers and structures passed to MEI bus and client API can be made const for safer code and clear indication that it is not modified. Acked-by: Arnd Bergmann Acked-by: Tomas Winkler Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20210729102803.46289-1-krzysztof.kozlowski@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/bus.c | 18 +++++++++--------- drivers/misc/mei/client.h | 2 +- drivers/misc/mei/mei_dev.h | 2 +- include/linux/mei_cl_bus.h | 9 +++++---- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 935acc6bbf3c..09188d9afc06 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -31,7 +31,7 @@ * * Return: written size bytes or < 0 on error */ -ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, u8 vtag, +ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag, unsigned int mode) { struct mei_device *bus; @@ -232,8 +232,8 @@ out: * * < 0 on error */ -ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, - u8 vtag) +ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, + size_t length, u8 vtag) { struct mei_cl *cl = cldev->cl; @@ -296,7 +296,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag); * * written size in bytes * * < 0 on error */ -ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length) +ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length) { return mei_cldev_send_vtag(cldev, buf, length, 0); } @@ -552,7 +552,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_ver); * * Return: true if me client is initialized and connected */ -bool mei_cldev_enabled(struct mei_cl_device *cldev) +bool mei_cldev_enabled(const struct mei_cl_device *cldev) { return mei_cl_is_connected(cldev->cl); } @@ -771,8 +771,8 @@ EXPORT_SYMBOL_GPL(mei_cldev_disable); * Return: id on success; NULL if no id is matching */ static const -struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev, - struct mei_cl_driver *cldrv) +struct mei_cl_device_id *mei_cl_device_find(const struct mei_cl_device *cldev, + const struct mei_cl_driver *cldrv) { const struct mei_cl_device_id *id; const uuid_le *uuid; @@ -815,8 +815,8 @@ struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev, */ static int mei_cl_device_match(struct device *dev, struct device_driver *drv) { - struct mei_cl_device *cldev = to_mei_cl_device(dev); - struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); + const struct mei_cl_device *cldev = to_mei_cl_device(dev); + const struct mei_cl_driver *cldrv = to_mei_cl_driver(drv); const struct mei_cl_device_id *found_id; if (!cldev) diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index b12cdcde9436..418056fb1489 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h @@ -160,7 +160,7 @@ int mei_cl_vt_support_check(const struct mei_cl *cl); * * Return: true if the host client is connected */ -static inline bool mei_cl_is_connected(struct mei_cl *cl) +static inline bool mei_cl_is_connected(const struct mei_cl *cl) { return cl->state == MEI_FILE_CONNECTED; } diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index b7b6ef344e80..694f866f87ef 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -356,7 +356,7 @@ struct mei_hw_ops { /* MEI bus API*/ void mei_cl_bus_rescan_work(struct work_struct *work); void mei_cl_bus_dev_fixup(struct mei_cl_device *dev); -ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, u8 vtag, +ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag, unsigned int mode); ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, u8 *vtag, unsigned int mode, unsigned long timeout); diff --git a/include/linux/mei_cl_bus.h b/include/linux/mei_cl_bus.h index 07f5ef8fc456..c6786c12b207 100644 --- a/include/linux/mei_cl_bus.h +++ b/include/linux/mei_cl_bus.h @@ -91,12 +91,13 @@ void mei_cldev_driver_unregister(struct mei_cl_driver *cldrv); mei_cldev_driver_register,\ mei_cldev_driver_unregister) -ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length); +ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, + size_t length); ssize_t mei_cldev_recv(struct mei_cl_device *cldev, u8 *buf, size_t length); ssize_t mei_cldev_recv_nonblock(struct mei_cl_device *cldev, u8 *buf, size_t length); -ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, - u8 vtag); +ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf, + size_t length, u8 vtag); ssize_t mei_cldev_recv_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length, u8 *vtag); ssize_t mei_cldev_recv_nonblock_vtag(struct mei_cl_device *cldev, u8 *buf, @@ -114,6 +115,6 @@ void mei_cldev_set_drvdata(struct mei_cl_device *cldev, void *data); int mei_cldev_enable(struct mei_cl_device *cldev); int mei_cldev_disable(struct mei_cl_device *cldev); -bool mei_cldev_enabled(struct mei_cl_device *cldev); +bool mei_cldev_enabled(const struct mei_cl_device *cldev); #endif /* _LINUX_MEI_CL_BUS_H */ -- cgit v1.2.3 From 09b18f2f3be256cc32eff028a9416a2ae19d5487 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 21 Jul 2021 18:02:15 +0300 Subject: parport: serial: Get rid of IRQ_NONE abuse IRQ_NONE definition is solely for IRQ handlers and not for generic probe code. Replace it with plain integer. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210721150216.64823-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_serial.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 96b888bb49c6..14e2427676f0 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -607,11 +607,12 @@ static int parport_register(struct pci_dev *dev, const struct pci_device_id *id) def.) */ /* TODO: test if sharing interrupts works */ irq = dev->irq; - if (irq == IRQ_NONE) { + if (irq == 0) + irq = PARPORT_IRQ_NONE; + if (irq == PARPORT_IRQ_NONE) { dev_dbg(&dev->dev, "PCI parallel port detected: I/O at %#lx(%#lx)\n", io_lo, io_hi); - irq = PARPORT_IRQ_NONE; } else { dev_dbg(&dev->dev, "PCI parallel port detected: I/O at %#lx(%#lx), IRQ %d\n", -- cgit v1.2.3 From fa11c81ce2a19b30af2fc16d3958efece4fd56d0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 21 Jul 2021 18:02:16 +0300 Subject: parport: serial: Retrieve IRQ vector with help of special getter pci_irq_vector() may be used to retrieve IRQ vector for a PCI device. Use it instead of direct access. Acked-by: Sudip Mukherjee Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210721150216.64823-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_serial.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index 14e2427676f0..9f5d784cd95d 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -606,7 +606,9 @@ static int parport_register(struct pci_dev *dev, const struct pci_device_id *id) "hi" as an offset (see SYBA def.) */ /* TODO: test if sharing interrupts works */ - irq = dev->irq; + irq = pci_irq_vector(dev, 0); + if (irq < 0) + return irq; if (irq == 0) irq = PARPORT_IRQ_NONE; if (irq == PARPORT_IRQ_NONE) { -- cgit v1.2.3 From 9b945d74a5fc14c1f9a7ae98c10921d48c194105 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 7 Jun 2021 18:37:29 +0300 Subject: pps: clients: parport: Switch to use module_parport_driver() Switch to use module_parport_driver() to reduce boilerplate code. Acked-by: Rodolfo Giometti Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210607153729.58623-1-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/pps/clients/pps_parport.c | 42 ++++++++------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c index 7a41fb7b0dec..42f93d4c6ee3 100644 --- a/drivers/pps/clients/pps_parport.c +++ b/drivers/pps/clients/pps_parport.c @@ -22,8 +22,6 @@ #include #include -#define DRVDESC "parallel port PPS client" - /* module parameters */ #define CLEAR_WAIT_MAX 100 @@ -138,6 +136,12 @@ static void parport_attach(struct parport *port) .dev = NULL }; + if (clear_wait > CLEAR_WAIT_MAX) { + pr_err("clear_wait value should be not greater then %d\n", + CLEAR_WAIT_MAX); + return; + } + device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL); if (!device) { pr_err("memory allocation failed, not attaching\n"); @@ -214,38 +218,8 @@ static struct parport_driver pps_parport_driver = { .detach = parport_detach, .devmodel = true, }; - -/* module staff */ - -static int __init pps_parport_init(void) -{ - int ret; - - pr_info(DRVDESC "\n"); - - if (clear_wait > CLEAR_WAIT_MAX) { - pr_err("clear_wait value should be not greater" - " then %d\n", CLEAR_WAIT_MAX); - return -EINVAL; - } - - ret = parport_register_driver(&pps_parport_driver); - if (ret) { - pr_err("unable to register with parport\n"); - return ret; - } - - return 0; -} - -static void __exit pps_parport_exit(void) -{ - parport_unregister_driver(&pps_parport_driver); -} - -module_init(pps_parport_init); -module_exit(pps_parport_exit); +module_parport_driver(pps_parport_driver); MODULE_AUTHOR("Alexander Gordeev "); -MODULE_DESCRIPTION(DRVDESC); +MODULE_DESCRIPTION("parallel port PPS client"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 5f1895e0e381f04ef759cd33636d861b0fdcb3d1 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 28 Jul 2021 22:51:50 +0100 Subject: fpga: Fix spelling mistake "eXchnage" -> "exchange" in Kconfig There is a spelling mistake in the Kconfig text. Fix it. Reviewed-by: Tom Rix Signed-off-by: Colin Ian King Signed-off-by: Moritz Fischer --- drivers/fpga/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index 8cd454ee20c0..3a33990e44fc 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -119,7 +119,7 @@ config XILINX_PR_DECOUPLER depends on HAS_IOMEM help Say Y to enable drivers for Xilinx LogiCORE PR Decoupler - or Xilinx Dynamic Function eXchnage AIX Shutdown Manager. + or Xilinx Dynamic Function eXchange AIX Shutdown Manager. The PR Decoupler exists in the FPGA fabric to isolate one region of the FPGA from the busses while that region is being reprogrammed during partial reconfig. -- cgit v1.2.3 From 1604986c3e6bd84f3f3fd709c1a619c6fc9d79a9 Mon Sep 17 00:00:00 2001 From: Martin Hundebøll Date: Fri, 16 Jul 2021 15:54:39 +0200 Subject: fpga: dfl: expose feature revision from struct dfl_device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DFL device drivers have a common need for checking feature revision information from the DFL header, as well as other common DFL information like the already exposed feature id and type. This patch exposes the feature revision information directly via the DFL device data structure. Since the DFL core code has already read the DFL header, this this patch saves additional mmio reads from DFL device drivers too. Acked-by: Wu Hao Acked-by: Matthew Gerlach Signed-off-by: Martin Hundebøll Signed-off-by: Moritz Fischer --- drivers/fpga/dfl.c | 27 +++++++++++++++++---------- drivers/fpga/dfl.h | 1 + include/linux/dfl.h | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c index 511b20ff35a3..e73a70053906 100644 --- a/drivers/fpga/dfl.c +++ b/drivers/fpga/dfl.c @@ -381,6 +381,7 @@ dfl_dev_add(struct dfl_feature_platform_data *pdata, ddev->type = feature_dev_id_type(pdev); ddev->feature_id = feature->id; + ddev->revision = feature->revision; ddev->cdev = pdata->dfl_cdev; /* add mmio resource */ @@ -717,6 +718,7 @@ struct build_feature_devs_info { */ struct dfl_feature_info { u16 fid; + u8 revision; struct resource mmio_res; void __iomem *ioaddr; struct list_head node; @@ -796,6 +798,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo) /* save resource information for each feature */ feature->dev = fdev; feature->id = finfo->fid; + feature->revision = finfo->revision; /* * the FIU header feature has some fundamental functions (sriov @@ -910,19 +913,17 @@ static void build_info_free(struct build_feature_devs_info *binfo) devm_kfree(binfo->dev, binfo); } -static inline u32 feature_size(void __iomem *start) +static inline u32 feature_size(u64 value) { - u64 v = readq(start + DFH); - u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, v); + u32 ofst = FIELD_GET(DFH_NEXT_HDR_OFST, value); /* workaround for private features with invalid size, use 4K instead */ return ofst ? ofst : 4096; } -static u16 feature_id(void __iomem *start) +static u16 feature_id(u64 value) { - u64 v = readq(start + DFH); - u16 id = FIELD_GET(DFH_ID, v); - u8 type = FIELD_GET(DFH_TYPE, v); + u16 id = FIELD_GET(DFH_ID, value); + u8 type = FIELD_GET(DFH_TYPE, value); if (type == DFH_TYPE_FIU) return FEATURE_ID_FIU_HEADER; @@ -1021,10 +1022,15 @@ create_feature_instance(struct build_feature_devs_info *binfo, unsigned int irq_base, nr_irqs; struct dfl_feature_info *finfo; int ret; + u8 revision; + u64 v; + + v = readq(binfo->ioaddr + ofst); + revision = FIELD_GET(DFH_REVISION, v); /* read feature size and id if inputs are invalid */ - size = size ? size : feature_size(binfo->ioaddr + ofst); - fid = fid ? fid : feature_id(binfo->ioaddr + ofst); + size = size ? size : feature_size(v); + fid = fid ? fid : feature_id(v); if (binfo->len - ofst < size) return -EINVAL; @@ -1038,6 +1044,7 @@ create_feature_instance(struct build_feature_devs_info *binfo, return -ENOMEM; finfo->fid = fid; + finfo->revision = revision; finfo->mmio_res.start = binfo->start + ofst; finfo->mmio_res.end = finfo->mmio_res.start + size - 1; finfo->mmio_res.flags = IORESOURCE_MEM; @@ -1166,7 +1173,7 @@ static int parse_feature_private(struct build_feature_devs_info *binfo, { if (!is_feature_dev_detected(binfo)) { dev_err(binfo->dev, "the private feature 0x%x does not belong to any AFU.\n", - feature_id(binfo->ioaddr + ofst)); + feature_id(readq(binfo->ioaddr + ofst))); return -EINVAL; } diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index dac9c3d45e6c..53572c7aced0 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -243,6 +243,7 @@ struct dfl_feature_irq_ctx { struct dfl_feature { struct platform_device *dev; u16 id; + u8 revision; int resource_index; void __iomem *ioaddr; struct dfl_feature_irq_ctx *irq_ctx; diff --git a/include/linux/dfl.h b/include/linux/dfl.h index 6cc10982351a..431636a0dc78 100644 --- a/include/linux/dfl.h +++ b/include/linux/dfl.h @@ -38,6 +38,7 @@ struct dfl_device { int id; u16 type; u16 feature_id; + u8 revision; struct resource mmio_res; int *irqs; unsigned int num_irqs; -- cgit v1.2.3 From 4f45f3404960109843eaa92c8a4a850d6bdd9981 Mon Sep 17 00:00:00 2001 From: Martin Hundebøll Date: Fri, 16 Jul 2021 15:54:40 +0200 Subject: spi: spi-altera-dfl: support n5010 feature revision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Max10 BMC on the Silicom n5010 PAC is slightly different than the existing BMCs, so use a dedicated feature revision detect it. Acked-by: Mark Brown Reviewed-by: Tom Rix Signed-off-by: Martin Hundebøll Signed-off-by: Moritz Fischer --- drivers/spi/spi-altera-dfl.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-altera-dfl.c b/drivers/spi/spi-altera-dfl.c index 39a3e1a032e0..44fc9ee13fc7 100644 --- a/drivers/spi/spi-altera-dfl.c +++ b/drivers/spi/spi-altera-dfl.c @@ -104,13 +104,6 @@ static const struct regmap_config indirect_regbus_cfg = { .reg_read = indirect_bus_reg_read, }; -static struct spi_board_info m10_bmc_info = { - .modalias = "m10-d5005", - .max_speed_hz = 12500000, - .bus_num = 0, - .chip_select = 0, -}; - static void config_spi_master(void __iomem *base, struct spi_master *master) { u64 v; @@ -130,6 +123,7 @@ static void config_spi_master(void __iomem *base, struct spi_master *master) static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) { + struct spi_board_info board_info = { 0 }; struct device *dev = &dfl_dev->dev; struct spi_master *master; struct altera_spi *hw; @@ -170,9 +164,18 @@ static int dfl_spi_altera_probe(struct dfl_device *dfl_dev) goto exit; } - if (!spi_new_device(master, &m10_bmc_info)) { + if (dfl_dev->revision == FME_FEATURE_REV_MAX10_SPI_N5010) + strscpy(board_info.modalias, "m10-n5010", SPI_NAME_SIZE); + else + strscpy(board_info.modalias, "m10-d5005", SPI_NAME_SIZE); + + board_info.max_speed_hz = 12500000; + board_info.bus_num = 0; + board_info.chip_select = 0; + + if (!spi_new_device(master, &board_info)) { dev_err(dev, "%s failed to create SPI device: %s\n", - __func__, m10_bmc_info.modalias); + __func__, board_info.modalias); } return 0; -- cgit v1.2.3 From 0fc7ca624b1452050d31b05cd198e38a1b74d1b3 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Sun, 1 Aug 2021 10:25:32 +0300 Subject: samples: mei: don't wait on read completion upon write. The original mei driver communication was strictly write command and receive response flow, the completion of write was determined when response was ready using select(). This paradigm is a long time not true. There can be write without a response and an unsolicited read. The driver is capable of handling those. Adjust also the sample code and remove select() on read() from the write flow. Add select to the read flow to showcase how to do the read with a timeout. Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Link: https://lore.kernel.org/r/20210801072532.8668-1-tomas.winkler@intel.com Signed-off-by: Greg Kroah-Hartman --- samples/mei/mei-amt-version.c | 51 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/samples/mei/mei-amt-version.c b/samples/mei/mei-amt-version.c index ad3e56042f96..867debd3b912 100644 --- a/samples/mei/mei-amt-version.c +++ b/samples/mei/mei-amt-version.c @@ -154,31 +154,52 @@ err: static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer, ssize_t len, unsigned long timeout) { + struct timeval tv; + fd_set set; ssize_t rc; + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000000; + mei_msg(me, "call read length = %zd\n", len); + FD_ZERO(&set); + FD_SET(me->fd, &set); + rc = select(me->fd + 1, &set, NULL, NULL, &tv); + if (rc > 0 && FD_ISSET(me->fd, &set)) { + mei_msg(me, "have reply\n"); + } else if (rc == 0) { + rc = -1; + mei_err(me, "read failed on timeout\n"); + goto out; + } else { /* rc < 0 */ + rc = errno; + mei_err(me, "read failed on select with status %zd %s\n", + rc, strerror(errno)); + goto out; + } + rc = read(me->fd, buffer, len); if (rc < 0) { mei_err(me, "read failed with status %zd %s\n", rc, strerror(errno)); - mei_deinit(me); - } else { - mei_msg(me, "read succeeded with result %zd\n", rc); + goto out; } + + mei_msg(me, "read succeeded with result %zd\n", rc); + +out: + if (rc < 0) + mei_deinit(me); + return rc; } static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer, ssize_t len, unsigned long timeout) { - struct timeval tv; ssize_t written; ssize_t rc; - fd_set set; - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000000; mei_msg(me, "call write length = %zd\n", len); @@ -189,19 +210,7 @@ static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer, written, strerror(errno)); goto out; } - - FD_ZERO(&set); - FD_SET(me->fd, &set); - rc = select(me->fd + 1 , &set, NULL, NULL, &tv); - if (rc > 0 && FD_ISSET(me->fd, &set)) { - mei_msg(me, "write success\n"); - } else if (rc == 0) { - mei_err(me, "write failed on timeout with status\n"); - goto out; - } else { /* rc < 0 */ - mei_err(me, "write failed on select with status %zd\n", rc); - goto out; - } + mei_msg(me, "write success\n"); rc = written; out: -- cgit v1.2.3 From ff560946ef15fb05b18a660f6b25e9c26fe050e1 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 13:13:49 +0800 Subject: soundwire: cadence: add paranoid check on self-clearing bits The Cadence IP exposes a small number of self-clearing bits in the MCP_CONTROL and MCP_CONFIG_UPDATE registers. We currently do not check that those bits are indeed cleared, e.g. during resume operations. That could lead to resuming peripheral devices too early. In addition, if we happen to read these registers, update one of the fields and write the register back, we may be writing stale data that might have been cleared in hardware. These sort of race conditions could lead to e.g. doing a hw_reset twice or stopping a clock that just restarted. There is no clear way of avoiding these potential race conditions other than making sure that these registers fields are cleared before any read-modify-write sequence. If we detect this sort of errors, we only log them since there is no clear recovery possible. The only way out is likely to restart the IP with a suspend/resume cycle. Note that the checks are performed before updating the registers, as well as after the Intel 'sync go' sequence in multi-link mode. That should cover both the start and end of suspend/resume hardware configurations. The Multi-Master mode gates the configuration updates until the 'sync go' signal is asserted, so we only check on init and after the end of the 'sync go' sequence. The duration of the usleep_range() was defined by the GSYNC frequency used in multi-master mode. With a 4kHz frequency, any configuration change might be deferred by up to 250us. Extending the range to 1000-1500us should guarantee that the configuration change is completed without any significant impact on the overall resume time. Suggested-by: Bard Liao Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714051349.13064-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 47 ++++++++++++++++++++++++++++++++++++++ drivers/soundwire/cadence_master.h | 4 ++++ drivers/soundwire/intel.c | 14 ++++++++++++ 3 files changed, 65 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 9a9b6110e763..a9bd56f0d534 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -935,6 +935,49 @@ static void cdns_update_slave_status_work(struct work_struct *work) } +/* paranoia check to make sure self-cleared bits are indeed cleared */ +void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, + bool initial_delay, int reset_iterations) +{ + u32 mcp_control; + u32 mcp_config_update; + int i; + + if (initial_delay) + usleep_range(1000, 1500); + + mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL); + + /* the following bits should be cleared immediately */ + if (mcp_control & CDNS_MCP_CONTROL_CMD_RST) + dev_err(cdns->dev, "%s failed: MCP_CONTROL_CMD_RST is not cleared\n", string); + if (mcp_control & CDNS_MCP_CONTROL_SOFT_RST) + dev_err(cdns->dev, "%s failed: MCP_CONTROL_SOFT_RST is not cleared\n", string); + if (mcp_control & CDNS_MCP_CONTROL_SW_RST) + dev_err(cdns->dev, "%s failed: MCP_CONTROL_SW_RST is not cleared\n", string); + if (mcp_control & CDNS_MCP_CONTROL_CLK_STOP_CLR) + dev_err(cdns->dev, "%s failed: MCP_CONTROL_CLK_STOP_CLR is not cleared\n", string); + mcp_config_update = cdns_readl(cdns, CDNS_MCP_CONFIG_UPDATE); + if (mcp_config_update & CDNS_MCP_CONFIG_UPDATE_BIT) + dev_err(cdns->dev, "%s failed: MCP_CONFIG_UPDATE_BIT is not cleared\n", string); + + i = 0; + while (mcp_control & CDNS_MCP_CONTROL_HW_RST) { + if (i == reset_iterations) { + dev_err(cdns->dev, "%s failed: MCP_CONTROL_HW_RST is not cleared\n", string); + break; + } + + dev_dbg(cdns->dev, "%s: MCP_CONTROL_HW_RST is not cleared at iteration %d\n", string, i); + i++; + + usleep_range(1000, 1500); + mcp_control = cdns_readl(cdns, CDNS_MCP_CONTROL); + } + +} +EXPORT_SYMBOL(sdw_cdns_check_self_clearing_bits); + /* * init routines */ @@ -1212,6 +1255,8 @@ int sdw_cdns_init(struct sdw_cdns *cdns) cdns_init_clock_ctrl(cdns); + sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0); + /* reset msg_count to default value of FIFOLEVEL */ cdns->msg_count = cdns_readl(cdns, CDNS_MCP_FIFOLEVEL); @@ -1396,6 +1441,8 @@ int sdw_cdns_clock_stop(struct sdw_cdns *cdns, bool block_wake) struct sdw_slave *slave; int ret; + sdw_cdns_check_self_clearing_bits(cdns, __func__, false, 0); + /* Check suspend status */ if (sdw_cdns_is_clock_stop(cdns)) { dev_dbg(cdns->dev, "Clock is already stopped\n"); diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index 0e7f8b35bb21..b54c161a837f 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -184,4 +184,8 @@ int cdns_bus_conf(struct sdw_bus *bus, struct sdw_bus_params *params); int cdns_set_sdw_stream(struct snd_soc_dai *dai, void *stream, bool pcm, int direction); + +void sdw_cdns_check_self_clearing_bits(struct sdw_cdns *cdns, const char *string, + bool initial_delay, int reset_iterations); + #endif /* __SDW_CADENCE_H */ diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index c11e3d8cd308..9794bc222fb5 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -23,6 +23,7 @@ #include "intel.h" #define INTEL_MASTER_SUSPEND_DELAY_MS 3000 +#define INTEL_MASTER_RESET_ITERATIONS 10 /* * debug/config flags for the Intel SoundWire Master. @@ -1467,6 +1468,8 @@ int intel_link_startup(struct auxiliary_device *auxdev) goto err_interrupt; } } + sdw_cdns_check_self_clearing_bits(cdns, __func__, + true, INTEL_MASTER_RESET_ITERATIONS); /* Register DAIs */ ret = intel_register_dai(sdw); @@ -1783,6 +1786,8 @@ static int __maybe_unused intel_resume(struct device *dev) return ret; } } + sdw_cdns_check_self_clearing_bits(cdns, __func__, + true, INTEL_MASTER_RESET_ITERATIONS); /* * after system resume, the pm_runtime suspend() may kick in @@ -1867,6 +1872,9 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) return ret; } } + sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime TEARDOWN", + true, INTEL_MASTER_RESET_ITERATIONS); + } else if (clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) { ret = intel_init(sdw); if (ret) { @@ -1940,6 +1948,9 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) } } } + sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime BUS_RESET", + true, INTEL_MASTER_RESET_ITERATIONS); + } else if (!clock_stop_quirks) { clock_stop0 = sdw_cdns_is_clock_stop(&sdw->cdns); @@ -1963,6 +1974,9 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) dev_err(dev, "unable to resume master during resume\n"); return ret; } + + sdw_cdns_check_self_clearing_bits(cdns, "intel_resume_runtime no_quirks", + true, INTEL_MASTER_RESET_ITERATIONS); } else { dev_err(dev, "%s clock_stop_quirks %x unsupported\n", __func__, clock_stop_quirks); -- cgit v1.2.3 From e6645314eb2747bef4d9a375997221dede8ce4ce Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 14 Jul 2021 11:22:04 +0800 Subject: soundwire: stream: don't abort bank switch on Command_Ignored/-ENODATA This change is needed for support of mockup devices, which by construction will not provide any answer to a bank switch, but it's also legit for regular cases. If for some reason a device loses sync and cannot handle a bank switch, we should go ahead anyways. The devices can always resync later. The only case where the error flow should be used is when there is a Command_Aborted composite answer from SoundWire devices. Signed-off-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20210714032209.11284-6-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index 1a18308f4ef4..d84aaf115c13 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -697,7 +697,7 @@ static int sdw_bank_switch(struct sdw_bus *bus, int m_rt_count) else ret = sdw_transfer(bus, wr_msg); - if (ret < 0) { + if (ret < 0 && ret != -ENODATA) { dev_err(bus->dev, "Slave frame_ctrl reg write failed\n"); goto error; } -- cgit v1.2.3 From 4a7a603cad3f667fb02e194c0a3412d3a7292093 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:05 +0800 Subject: soundwire: add flag to ignore all command/control for mockup devices SoundWire mockup devices don't take part in the command/control protocol, so all commands will complete with -ENODATA or Command_Ignored results. With a flag, we can suppress such errors in the bus management and make it appear as if all read/writes succeed. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-7-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- include/linux/soundwire/sdw.h | 3 +++ sound/soc/codecs/sdw-mockup.c | 2 ++ 2 files changed, 5 insertions(+) diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index a48ac3e77301..76ce3f3ac0f2 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -661,6 +661,8 @@ struct sdw_slave_ops { * initialized * @first_interrupt_done: status flag tracking if the interrupt handling * for a Slave happens for the first time after enumeration + * @is_mockup_device: status flag used to squelch errors in the command/control + * protocol for SoundWire mockup devices */ struct sdw_slave { struct sdw_slave_id id; @@ -683,6 +685,7 @@ struct sdw_slave { struct completion initialization_complete; u32 unattach_request; bool first_interrupt_done; + bool is_mockup_device; }; #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) diff --git a/sound/soc/codecs/sdw-mockup.c b/sound/soc/codecs/sdw-mockup.c index a4f79eb2c69d..8ea13cfa9f8e 100644 --- a/sound/soc/codecs/sdw-mockup.c +++ b/sound/soc/codecs/sdw-mockup.c @@ -263,6 +263,8 @@ static int sdw_mockup_sdw_probe(struct sdw_slave *slave, dev_set_drvdata(dev, sdw_mockup); sdw_mockup->slave = slave; + slave->is_mockup_device = true; + ret = devm_snd_soc_register_component(dev, &snd_soc_sdw_mockup_component, sdw_mockup_dai, -- cgit v1.2.3 From 7fae3cfb7007038a320db43ddffb7688388a0260 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:06 +0800 Subject: soundwire: bus: squelch error returned by mockup devices All read and writes from/to SoundWire mockup devices will return -ENODATA/Command_Ignored, this patch forces a Command_OK result to let the bus perform the required configurations, e.g. for the Data Ports, which will only have an effect on the Master side. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-8-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/bus.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/soundwire/bus.c b/drivers/soundwire/bus.c index b3ed0123ed27..1b115734a8f6 100644 --- a/drivers/soundwire/bus.c +++ b/drivers/soundwire/bus.c @@ -390,7 +390,10 @@ sdw_nread_no_pm(struct sdw_slave *slave, u32 addr, size_t count, u8 *val) if (ret < 0) return ret; - return sdw_transfer(slave->bus, &msg); + ret = sdw_transfer(slave->bus, &msg); + if (slave->is_mockup_device) + ret = 0; + return ret; } static int @@ -404,7 +407,10 @@ sdw_nwrite_no_pm(struct sdw_slave *slave, u32 addr, size_t count, const u8 *val) if (ret < 0) return ret; - return sdw_transfer(slave->bus, &msg); + ret = sdw_transfer(slave->bus, &msg); + if (slave->is_mockup_device) + ret = 0; + return ret; } int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value) -- cgit v1.2.3 From 24f08b3aa5a5e42977c5a1d711d5cb7d9adbd94d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 14 Jul 2021 11:22:07 +0800 Subject: soundwire: stream: don't program mockup device ports Mockup devices don't take part in command/control operations and their virtual ports shall not be programmed. Signed-off-by: Bard Liao Reviewed-by: Rander Wang Link: https://lore.kernel.org/r/20210714032209.11284-9-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/stream.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soundwire/stream.c b/drivers/soundwire/stream.c index d84aaf115c13..5d4f6b308ef7 100644 --- a/drivers/soundwire/stream.c +++ b/drivers/soundwire/stream.c @@ -133,6 +133,9 @@ static int sdw_program_slave_port_params(struct sdw_bus *bus, int ret; u8 wbuf; + if (s_rt->slave->is_mockup_device) + return 0; + dpn_prop = sdw_get_slave_dpn_prop(s_rt->slave, s_rt->direction, t_params->port_num); -- cgit v1.2.3 From 8fba8acd399b70aeb262983d32baa9cbbf7dc981 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:08 +0800 Subject: soundwire: cadence: add debugfs interface for PDI loopbacks For debug, it's interesting to create a loopback stream for each link and use debugfs to set a source and target PDI. The target PDI would need to be an RX port and use the same register configurations as the source PDI. This capability allows e.g. for the headphone playback stream to be snooped on the headset capture stream, or alternatively for the addition of a dedicated loopback stream, in addition of regular capture for that link. This patch only adds the debugfs part, the port/PDI handling will be handled in the next patches. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-10-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 44 ++++++++++++++++++++++++++++++++++++++ drivers/soundwire/cadence_master.h | 3 +++ 2 files changed, 47 insertions(+) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index a9bd56f0d534..3670c0ebcace 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -450,6 +450,40 @@ static int cdns_parity_error_injection(void *data, u64 value) DEFINE_DEBUGFS_ATTRIBUTE(cdns_parity_error_fops, NULL, cdns_parity_error_injection, "%llu\n"); +static int cdns_set_pdi_loopback_source(void *data, u64 value) +{ + struct sdw_cdns *cdns = data; + unsigned int pdi_out_num = cdns->pcm.num_bd + cdns->pcm.num_out; + + if (value > pdi_out_num) + return -EINVAL; + + /* Userspace changed the hardware state behind the kernel's back */ + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + + cdns->pdi_loopback_source = value; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_source_fops, NULL, cdns_set_pdi_loopback_source, "%llu\n"); + +static int cdns_set_pdi_loopback_target(void *data, u64 value) +{ + struct sdw_cdns *cdns = data; + unsigned int pdi_in_num = cdns->pcm.num_bd + cdns->pcm.num_in; + + if (value > pdi_in_num) + return -EINVAL; + + /* Userspace changed the hardware state behind the kernel's back */ + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + + cdns->pdi_loopback_target = value; + + return 0; +} +DEFINE_DEBUGFS_ATTRIBUTE(cdns_pdi_loopback_target_fops, NULL, cdns_set_pdi_loopback_target, "%llu\n"); + /** * sdw_cdns_debugfs_init() - Cadence debugfs init * @cdns: Cadence instance @@ -464,6 +498,16 @@ void sdw_cdns_debugfs_init(struct sdw_cdns *cdns, struct dentry *root) debugfs_create_file("cdns-parity-error-injection", 0200, root, cdns, &cdns_parity_error_fops); + + cdns->pdi_loopback_source = -1; + cdns->pdi_loopback_target = -1; + + debugfs_create_file("cdns-pdi-loopback-source", 0200, root, cdns, + &cdns_pdi_loopback_source_fops); + + debugfs_create_file("cdns-pdi-loopback-target", 0200, root, cdns, + &cdns_pdi_loopback_target_fops); + } EXPORT_SYMBOL_GPL(sdw_cdns_debugfs_init); diff --git a/drivers/soundwire/cadence_master.h b/drivers/soundwire/cadence_master.h index b54c161a837f..e587aede63bf 100644 --- a/drivers/soundwire/cadence_master.h +++ b/drivers/soundwire/cadence_master.h @@ -129,6 +129,9 @@ struct sdw_cdns { struct sdw_cdns_streams pcm; struct sdw_cdns_streams pdm; + int pdi_loopback_source; + int pdi_loopback_target; + void __iomem *registers; bool link_up; -- cgit v1.2.3 From dd81e7c3f0bb4fbe48b770b389ab6ccb95058dab Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 14 Jul 2021 11:22:09 +0800 Subject: soundwire: cadence: override PDI configurations to create loopback When we set a source PDI, the target PDI parameters will be overridden by the source register values. The loopback streams can be independently enabled on each link. While the loopback source and target can be configured before any stream is active on each link, the loopback stream should only be prepared/triggered when the playback stream is prepared. Otherwise all registers might be programmed to their reset values and the loopback will not succeed. The SoundWire bus driver currently does not allow two streams to be triggered at the same time, so the playback will have to be started first, and later the loopback. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210714032209.11284-11-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 130 +++++++++++++++++++++++++++---------- 1 file changed, 95 insertions(+), 35 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 3670c0ebcace..0b7f037e6cd0 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1374,20 +1374,37 @@ static int cdns_port_params(struct sdw_bus *bus, struct sdw_port_params *p_params, unsigned int bank) { struct sdw_cdns *cdns = bus_to_cdns(bus); - int dpn_config = 0, dpn_config_off; + int dpn_config_off_source; + int dpn_config_off_target; + int target_num = p_params->num; + int source_num = p_params->num; + bool override = false; + int dpn_config; + + if (target_num == cdns->pdi_loopback_target && + cdns->pdi_loopback_source != -1) { + source_num = cdns->pdi_loopback_source; + override = true; + } - if (bank) - dpn_config_off = CDNS_DPN_B1_CONFIG(p_params->num); - else - dpn_config_off = CDNS_DPN_B0_CONFIG(p_params->num); + if (bank) { + dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num); + dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num); + } else { + dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num); + dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num); + } - dpn_config = cdns_readl(cdns, dpn_config_off); + dpn_config = cdns_readl(cdns, dpn_config_off_source); - u32p_replace_bits(&dpn_config, (p_params->bps - 1), CDNS_DPN_CONFIG_WL); - u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW); - u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT); + /* use port params if there is no loopback, otherwise use source as is */ + if (!override) { + u32p_replace_bits(&dpn_config, p_params->bps - 1, CDNS_DPN_CONFIG_WL); + u32p_replace_bits(&dpn_config, p_params->flow_mode, CDNS_DPN_CONFIG_PORT_FLOW); + u32p_replace_bits(&dpn_config, p_params->data_mode, CDNS_DPN_CONFIG_PORT_DAT); + } - cdns_writel(cdns, dpn_config_off, dpn_config); + cdns_writel(cdns, dpn_config_off_target, dpn_config); return 0; } @@ -1397,11 +1414,27 @@ static int cdns_transport_params(struct sdw_bus *bus, enum sdw_reg_bank bank) { struct sdw_cdns *cdns = bus_to_cdns(bus); - int dpn_offsetctrl = 0, dpn_offsetctrl_off; - int dpn_config = 0, dpn_config_off; - int dpn_hctrl = 0, dpn_hctrl_off; - int num = t_params->port_num; - int dpn_samplectrl_off; + int dpn_config; + int dpn_config_off_source; + int dpn_config_off_target; + int dpn_hctrl; + int dpn_hctrl_off_source; + int dpn_hctrl_off_target; + int dpn_offsetctrl; + int dpn_offsetctrl_off_source; + int dpn_offsetctrl_off_target; + int dpn_samplectrl; + int dpn_samplectrl_off_source; + int dpn_samplectrl_off_target; + int source_num = t_params->port_num; + int target_num = t_params->port_num; + bool override = false; + + if (target_num == cdns->pdi_loopback_target && + cdns->pdi_loopback_source != -1) { + source_num = cdns->pdi_loopback_source; + override = true; + } /* * Note: Only full data port is supported on the Master side for @@ -1409,32 +1442,59 @@ static int cdns_transport_params(struct sdw_bus *bus, */ if (bank) { - dpn_config_off = CDNS_DPN_B1_CONFIG(num); - dpn_samplectrl_off = CDNS_DPN_B1_SAMPLE_CTRL(num); - dpn_hctrl_off = CDNS_DPN_B1_HCTRL(num); - dpn_offsetctrl_off = CDNS_DPN_B1_OFFSET_CTRL(num); + dpn_config_off_source = CDNS_DPN_B1_CONFIG(source_num); + dpn_hctrl_off_source = CDNS_DPN_B1_HCTRL(source_num); + dpn_offsetctrl_off_source = CDNS_DPN_B1_OFFSET_CTRL(source_num); + dpn_samplectrl_off_source = CDNS_DPN_B1_SAMPLE_CTRL(source_num); + + dpn_config_off_target = CDNS_DPN_B1_CONFIG(target_num); + dpn_hctrl_off_target = CDNS_DPN_B1_HCTRL(target_num); + dpn_offsetctrl_off_target = CDNS_DPN_B1_OFFSET_CTRL(target_num); + dpn_samplectrl_off_target = CDNS_DPN_B1_SAMPLE_CTRL(target_num); + } else { - dpn_config_off = CDNS_DPN_B0_CONFIG(num); - dpn_samplectrl_off = CDNS_DPN_B0_SAMPLE_CTRL(num); - dpn_hctrl_off = CDNS_DPN_B0_HCTRL(num); - dpn_offsetctrl_off = CDNS_DPN_B0_OFFSET_CTRL(num); + dpn_config_off_source = CDNS_DPN_B0_CONFIG(source_num); + dpn_hctrl_off_source = CDNS_DPN_B0_HCTRL(source_num); + dpn_offsetctrl_off_source = CDNS_DPN_B0_OFFSET_CTRL(source_num); + dpn_samplectrl_off_source = CDNS_DPN_B0_SAMPLE_CTRL(source_num); + + dpn_config_off_target = CDNS_DPN_B0_CONFIG(target_num); + dpn_hctrl_off_target = CDNS_DPN_B0_HCTRL(target_num); + dpn_offsetctrl_off_target = CDNS_DPN_B0_OFFSET_CTRL(target_num); + dpn_samplectrl_off_target = CDNS_DPN_B0_SAMPLE_CTRL(target_num); } - dpn_config = cdns_readl(cdns, dpn_config_off); - u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC); - u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM); - cdns_writel(cdns, dpn_config_off, dpn_config); + dpn_config = cdns_readl(cdns, dpn_config_off_source); + if (!override) { + u32p_replace_bits(&dpn_config, t_params->blk_grp_ctrl, CDNS_DPN_CONFIG_BGC); + u32p_replace_bits(&dpn_config, t_params->blk_pkg_mode, CDNS_DPN_CONFIG_BPM); + } + cdns_writel(cdns, dpn_config_off_target, dpn_config); - u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1); - u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2); - cdns_writel(cdns, dpn_offsetctrl_off, dpn_offsetctrl); + if (!override) { + dpn_offsetctrl = 0; + u32p_replace_bits(&dpn_offsetctrl, t_params->offset1, CDNS_DPN_OFFSET_CTRL_1); + u32p_replace_bits(&dpn_offsetctrl, t_params->offset2, CDNS_DPN_OFFSET_CTRL_2); + } else { + dpn_offsetctrl = cdns_readl(cdns, dpn_offsetctrl_off_source); + } + cdns_writel(cdns, dpn_offsetctrl_off_target, dpn_offsetctrl); - u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART); - u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP); - u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL); + if (!override) { + dpn_hctrl = 0; + u32p_replace_bits(&dpn_hctrl, t_params->hstart, CDNS_DPN_HCTRL_HSTART); + u32p_replace_bits(&dpn_hctrl, t_params->hstop, CDNS_DPN_HCTRL_HSTOP); + u32p_replace_bits(&dpn_hctrl, t_params->lane_ctrl, CDNS_DPN_HCTRL_LCTRL); + } else { + dpn_hctrl = cdns_readl(cdns, dpn_hctrl_off_source); + } + cdns_writel(cdns, dpn_hctrl_off_target, dpn_hctrl); - cdns_writel(cdns, dpn_hctrl_off, dpn_hctrl); - cdns_writel(cdns, dpn_samplectrl_off, (t_params->sample_interval - 1)); + if (!override) + dpn_samplectrl = t_params->sample_interval - 1; + else + dpn_samplectrl = cdns_readl(cdns, dpn_samplectrl_off_source); + cdns_writel(cdns, dpn_samplectrl_off_target, dpn_samplectrl); return 0; } -- cgit v1.2.3 From 1ae14df56cc3e87d56f3c159803a289021f8ef7d Mon Sep 17 00:00:00 2001 From: Ramji Jiyani Date: Mon, 2 Aug 2021 22:04:45 +0000 Subject: binder: Add invalid handle info in user error log In the case of a failed transaction, only the thread and process id are logged. Add the handle info for the reference to the target node in user error log to aid debugging. Acked-by: Todd Kjos Signed-off-by: Ramji Jiyani Link: https://lore.kernel.org/r/20210802220446.1938347-1-ramjiyani@google.com Signed-off-by: Greg Kroah-Hartman --- drivers/android/binder.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index bcec598b89f2..d9030cb6b1e4 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2547,8 +2547,8 @@ static void binder_transaction(struct binder_proc *proc, ref->node, &target_proc, &return_error); } else { - binder_user_error("%d:%d got transaction to invalid handle\n", - proc->pid, thread->pid); + binder_user_error("%d:%d got transaction to invalid handle, %u\n", + proc->pid, thread->pid, tr->target.handle); return_error = BR_FAILED_REPLY; } binder_proc_unlock(proc); -- cgit v1.2.3 From e67adaa1754d5383583c35a703518507e457482b Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 3 Aug 2021 16:15:59 +0200 Subject: sgi-xpc: Replace deprecated CPU-hotplug functions. The functions get_online_cpus() and put_online_cpus() have been deprecated during the CPU hotplug rework. They map directly to cpus_read_lock() and cpus_read_unlock(). Replace deprecated CPU-hotplug functions with the official version. The behavior remains unchanged. Cc: Robin Holt Cc: Steve Wahl Cc: Mike Travis Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Signed-off-by: Sebastian Andrzej Siewior Link: https://lore.kernel.org/r/20210803141621.780504-17-bigeasy@linutronix.de Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sgi-xp/xpc_uv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 7791bde81a36..ba9ae0e2df0f 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -1742,7 +1742,7 @@ xpc_init_mq_node(int nid) { int cpu; - get_online_cpus(); + cpus_read_lock(); for_each_cpu(cpu, cpumask_of_node(nid)) { xpc_activate_mq_uv = @@ -1753,7 +1753,7 @@ xpc_init_mq_node(int nid) break; } if (IS_ERR(xpc_activate_mq_uv)) { - put_online_cpus(); + cpus_read_unlock(); return PTR_ERR(xpc_activate_mq_uv); } @@ -1767,11 +1767,11 @@ xpc_init_mq_node(int nid) } if (IS_ERR(xpc_notify_mq_uv)) { xpc_destroy_gru_mq_uv(xpc_activate_mq_uv); - put_online_cpus(); + cpus_read_unlock(); return PTR_ERR(xpc_notify_mq_uv); } - put_online_cpus(); + cpus_read_unlock(); return 0; } -- cgit v1.2.3 From fec29bf04994b478a43a7e60e6dd5ac1f7cb53ae Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Thu, 15 Jul 2021 13:34:23 +0300 Subject: misc: sram: Only map reserved areas in Tegra SYSRAM On Tegra186 and later, a portion of the SYSRAM may be reserved for use by TZ. Non-TZ memory accesses to this portion, including speculative accesses, trigger SErrors that bring down the system. This does also happen in practice occasionally (due to speculative accesses). To fix the issue, add a flag to the SRAM driver to only map the device tree-specified reserved areas depending on a flag set based on the compatibility string. This would not affect non-Tegra systems that rely on the entire thing being memory mapped. If 64K pages are being used, we cannot exactly map the 4K regions that are placed in SYSRAM - ioremap code instead aligns to closest 64K pages. However, since in practice the non-accessible memory area is 64K aligned, these mappings do not overlap with the non-accessible memory area and things work out. Reviewed-by: Mian Yousaf Kaukab Signed-off-by: Mikko Perttunen Link: https://lore.kernel.org/r/20210715103423.1811101-1-mperttunen@nvidia.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/sram.c | 103 +++++++++++++++++++++++++++++++++++++--------------- drivers/misc/sram.h | 9 +++++ 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index 93638ae2753a..4c26b19f5154 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -97,7 +97,24 @@ static int sram_add_partition(struct sram_dev *sram, struct sram_reserve *block, struct sram_partition *part = &sram->partition[sram->partitions]; mutex_init(&part->lock); - part->base = sram->virt_base + block->start; + + if (sram->config && sram->config->map_only_reserved) { + void __iomem *virt_base; + + if (sram->no_memory_wc) + virt_base = devm_ioremap_resource(sram->dev, &block->res); + else + virt_base = devm_ioremap_resource_wc(sram->dev, &block->res); + + if (IS_ERR(virt_base)) { + dev_err(sram->dev, "could not map SRAM at %pr\n", &block->res); + return PTR_ERR(virt_base); + } + + part->base = virt_base; + } else { + part->base = sram->virt_base + block->start; + } if (block->pool) { ret = sram_add_pool(sram, block, start, part); @@ -198,6 +215,7 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) block->start = child_res.start - res->start; block->size = resource_size(&child_res); + block->res = child_res; list_add_tail(&block->list, &reserve_list); if (of_find_property(child, "export", NULL)) @@ -295,15 +313,17 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) */ cur_size = block->start - cur_start; - dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n", - cur_start, cur_start + cur_size); + if (sram->pool) { + dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n", + cur_start, cur_start + cur_size); - ret = gen_pool_add_virt(sram->pool, - (unsigned long)sram->virt_base + cur_start, - res->start + cur_start, cur_size, -1); - if (ret < 0) { - sram_free_partitions(sram); - goto err_chunks; + ret = gen_pool_add_virt(sram->pool, + (unsigned long)sram->virt_base + cur_start, + res->start + cur_start, cur_size, -1); + if (ret < 0) { + sram_free_partitions(sram); + goto err_chunks; + } } /* next allocation after this reserved block */ @@ -331,40 +351,63 @@ static int atmel_securam_wait(void) 10000, 500000); } +static const struct sram_config atmel_securam_config = { + .init = atmel_securam_wait, +}; + +/* + * SYSRAM contains areas that are not accessible by the + * kernel, such as the first 256K that is reserved for TZ. + * Accesses to those areas (including speculative accesses) + * trigger SErrors. As such we must map only the areas of + * SYSRAM specified in the device tree. + */ +static const struct sram_config tegra_sysram_config = { + .map_only_reserved = true, +}; + static const struct of_device_id sram_dt_ids[] = { { .compatible = "mmio-sram" }, - { .compatible = "atmel,sama5d2-securam", .data = atmel_securam_wait }, + { .compatible = "atmel,sama5d2-securam", .data = &atmel_securam_config }, + { .compatible = "nvidia,tegra186-sysram", .data = &tegra_sysram_config }, + { .compatible = "nvidia,tegra194-sysram", .data = &tegra_sysram_config }, {} }; static int sram_probe(struct platform_device *pdev) { + const struct sram_config *config; struct sram_dev *sram; int ret; struct resource *res; - int (*init_func)(void); + + config = of_device_get_match_data(&pdev->dev); sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL); if (!sram) return -ENOMEM; sram->dev = &pdev->dev; + sram->no_memory_wc = of_property_read_bool(pdev->dev.of_node, "no-memory-wc"); + sram->config = config; + + if (!config || !config->map_only_reserved) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (sram->no_memory_wc) + sram->virt_base = devm_ioremap_resource(&pdev->dev, res); + else + sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res); + if (IS_ERR(sram->virt_base)) { + dev_err(&pdev->dev, "could not map SRAM registers\n"); + return PTR_ERR(sram->virt_base); + } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc")) - sram->virt_base = devm_ioremap_resource(&pdev->dev, res); - else - sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res); - if (IS_ERR(sram->virt_base)) { - dev_err(&pdev->dev, "could not map SRAM registers\n"); - return PTR_ERR(sram->virt_base); + sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY), + NUMA_NO_NODE, NULL); + if (IS_ERR(sram->pool)) + return PTR_ERR(sram->pool); } - sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY), - NUMA_NO_NODE, NULL); - if (IS_ERR(sram->pool)) - return PTR_ERR(sram->pool); - sram->clk = devm_clk_get(sram->dev, NULL); if (IS_ERR(sram->clk)) sram->clk = NULL; @@ -378,15 +421,15 @@ static int sram_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sram); - init_func = of_device_get_match_data(&pdev->dev); - if (init_func) { - ret = init_func(); + if (config && config->init) { + ret = config->init(); if (ret) goto err_free_partitions; } - dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n", - gen_pool_size(sram->pool) / 1024, sram->virt_base); + if (sram->pool) + dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n", + gen_pool_size(sram->pool) / 1024, sram->virt_base); return 0; @@ -405,7 +448,7 @@ static int sram_remove(struct platform_device *pdev) sram_free_partitions(sram); - if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool)) + if (sram->pool && gen_pool_avail(sram->pool) < gen_pool_size(sram->pool)) dev_err(sram->dev, "removed while SRAM allocated\n"); if (sram->clk) diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h index 9c1d21ff7347..d2058d8c8f1d 100644 --- a/drivers/misc/sram.h +++ b/drivers/misc/sram.h @@ -5,6 +5,11 @@ #ifndef __SRAM_H #define __SRAM_H +struct sram_config { + int (*init)(void); + bool map_only_reserved; +}; + struct sram_partition { void __iomem *base; @@ -15,8 +20,11 @@ struct sram_partition { }; struct sram_dev { + const struct sram_config *config; + struct device *dev; void __iomem *virt_base; + bool no_memory_wc; struct gen_pool *pool; struct clk *clk; @@ -29,6 +37,7 @@ struct sram_reserve { struct list_head list; u32 start; u32 size; + struct resource res; bool export; bool pool; bool protect_exec; -- cgit v1.2.3 From 0092a1e3f7636ff4e202a41b0320690699247e22 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 2 Aug 2021 10:42:46 +0530 Subject: bus: mhi: Add inbound buffers allocation flag Currently, the MHI controller driver defines which channels should have their inbound buffers allocated and queued. But ideally, this is something that should be decided by the MHI device driver instead, which actually deals with that buffers. Add a flag parameter to mhi_prepare_for_transfer allowing to specify if buffers have to be allocated and queued by the MHI stack. Keep auto_queue flag for now, but should be removed at some point. Link: https://lore.kernel.org/r/1624566520-20406-1-git-send-email-loic.poulain@linaro.org Tested-by: Bhaumik Bhatt Reviewed-by: Bhaumik Bhatt Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Acked-by: Jakub Kicinski Signed-off-by: Loic Poulain Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-2-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/internal.h | 2 +- drivers/bus/mhi/core/main.c | 9 ++++++--- drivers/net/mhi/net.c | 2 +- drivers/net/wwan/mhi_wwan_ctrl.c | 2 +- include/linux/mhi.h | 7 ++++++- net/qrtr/mhi.c | 2 +- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 5b9ea66b92dc..bc239a11aa69 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -682,7 +682,7 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info); void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl); int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan); + struct mhi_chan *mhi_chan, unsigned int flags); int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index fc9196f11cb7..26bbc812121d 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1430,7 +1430,7 @@ exit_unprepare_channel: } int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan) + struct mhi_chan *mhi_chan, unsigned int flags) { int ret = 0; struct device *dev = &mhi_chan->mhi_dev->dev; @@ -1455,6 +1455,9 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, if (ret) goto error_pm_state; + if (mhi_chan->dir == DMA_FROM_DEVICE) + mhi_chan->pre_alloc = !!(flags & MHI_CH_INBOUND_ALLOC_BUFS); + /* Pre-allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { int nr_el = get_nr_avail_ring_elements(mhi_cntrl, @@ -1610,7 +1613,7 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) } /* Move channel to start state */ -int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, unsigned int flags) { int ret, dir; struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; @@ -1621,7 +1624,7 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) if (!mhi_chan) continue; - ret = mhi_prepare_channel(mhi_cntrl, mhi_chan); + ret = mhi_prepare_channel(mhi_cntrl, mhi_chan, flags); if (ret) goto error_open_chan; } diff --git a/drivers/net/mhi/net.c b/drivers/net/mhi/net.c index e60e38c1f09d..11be6bcdd551 100644 --- a/drivers/net/mhi/net.c +++ b/drivers/net/mhi/net.c @@ -335,7 +335,7 @@ static int mhi_net_newlink(void *ctxt, struct net_device *ndev, u32 if_id, u64_stats_init(&mhi_netdev->stats.tx_syncp); /* Start MHI channels */ - err = mhi_prepare_for_transfer(mhi_dev); + err = mhi_prepare_for_transfer(mhi_dev, 0); if (err) goto out_err; diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c index 1bc6b69aa530..1e18420ce404 100644 --- a/drivers/net/wwan/mhi_wwan_ctrl.c +++ b/drivers/net/wwan/mhi_wwan_ctrl.c @@ -110,7 +110,7 @@ static int mhi_wwan_ctrl_start(struct wwan_port *port) int ret; /* Start mhi device's channel(s) */ - ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev); + ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev, 0); if (ret) return ret; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 944aa3aa3035..5e08468854db 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -719,8 +719,13 @@ void mhi_device_put(struct mhi_device *mhi_dev); * host and device execution environments match and * channels are in a DISABLED state. * @mhi_dev: Device associated with the channels + * @flags: MHI channel flags */ -int mhi_prepare_for_transfer(struct mhi_device *mhi_dev); +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, + unsigned int flags); + +/* Automatically allocate and queue inbound buffers */ +#define MHI_CH_INBOUND_ALLOC_BUFS BIT(0) /** * mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer. diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index fa611678af05..29b4fa3b72ab 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -79,7 +79,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, int rc; /* start channels */ - rc = mhi_prepare_for_transfer(mhi_dev); + rc = mhi_prepare_for_transfer(mhi_dev, MHI_CH_INBOUND_ALLOC_BUFS); if (rc) return rc; -- cgit v1.2.3 From 87693e092bd06aa25686ed3db7aed460e144849d Mon Sep 17 00:00:00 2001 From: ULRICH Thomas Date: Mon, 2 Aug 2021 10:42:47 +0530 Subject: bus: mhi: pci_generic: Add Cinterion MV31-W PCIe to MHI This patch adds VendorID/ProductID and MBIM Channel Definitions for M.2 Modem Card (PCIe Variant) to MHI PCI generic controller driver. Cinterion MV31-W (by Thales) Additional information on such Modem Card (USB or PCIe variant) is available at: https://www.thalesgroup.com/en/markets/digital-identity-and-security/iot/iot-connectivity/products/iot-products/mv31-w-ultra-high Link: https://lore.kernel.org/r/PAZP264MB284690134DA010698E6B3BDDE60A9@PAZP264MB2846.FRAP264.PROD.OUTLOOK.COM [mani: fixed the subject, whitespace, and added sideband_wake field] Reviewed-by: Manivannan Sadhasivam Signed-off-by: ULRICH Thomas Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-3-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/pci_generic.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 4dd1077354af..5872c42927b1 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -366,6 +366,40 @@ static const struct mhi_pci_dev_info mhi_foxconn_sdx55_info = { .sideband_wake = false, }; +static const struct mhi_channel_config mhi_mv31_channels[] = { + MHI_CHANNEL_CONFIG_UL(0, "LOOPBACK", 64, 0), + MHI_CHANNEL_CONFIG_DL(1, "LOOPBACK", 64, 0), + /* MBIM Control Channel */ + MHI_CHANNEL_CONFIG_UL(12, "MBIM", 64, 0), + MHI_CHANNEL_CONFIG_DL(13, "MBIM", 64, 0), + /* MBIM Data Channel */ + MHI_CHANNEL_CONFIG_HW_UL(100, "IP_HW0_MBIM", 512, 2), + MHI_CHANNEL_CONFIG_HW_DL(101, "IP_HW0_MBIM", 512, 3), +}; + +static struct mhi_event_config mhi_mv31_events[] = { + MHI_EVENT_CONFIG_CTRL(0, 256), + MHI_EVENT_CONFIG_DATA(1, 256), + MHI_EVENT_CONFIG_HW_DATA(2, 1024, 100), + MHI_EVENT_CONFIG_HW_DATA(3, 1024, 101), +}; + +static const struct mhi_controller_config modem_mv31_config = { + .max_channels = 128, + .timeout_ms = 20000, + .num_channels = ARRAY_SIZE(mhi_mv31_channels), + .ch_cfg = mhi_mv31_channels, + .num_events = ARRAY_SIZE(mhi_mv31_events), + .event_cfg = mhi_mv31_events, +}; + +static const struct mhi_pci_dev_info mhi_mv31_info = { + .name = "cinterion-mv31", + .config = &modem_mv31_config, + .bar_num = MHI_PCI_DEFAULT_BAR_NUM, + .dma_data_width = 32, +}; + static const struct pci_device_id mhi_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_QCOM, 0x0306), .driver_data = (kernel_ulong_t) &mhi_qcom_sdx55_info }, @@ -386,6 +420,9 @@ static const struct pci_device_id mhi_pci_id_table[] = { /* DW5930e (sdx55), Non-eSIM, It's also T99W175 */ { PCI_DEVICE(PCI_VENDOR_ID_FOXCONN, 0xe0b1), .driver_data = (kernel_ulong_t) &mhi_foxconn_sdx55_info }, + /* MV31-W (Cinterion) */ + { PCI_DEVICE(0x1269, 0x00b3), + .driver_data = (kernel_ulong_t) &mhi_mv31_info }, { } }; MODULE_DEVICE_TABLE(pci, mhi_pci_id_table); -- cgit v1.2.3 From 3215d8e0691b4fc3ec26b44759e751cc05b8e2c5 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:48 +0530 Subject: bus: mhi: core: Set BHI/BHIe offsets on power up preparation Set the BHI and/or BHIe offsets in mhi_prepare_for_power_up(), rearrange the function, and remove the equivalent from mhi_async_power_up(). This helps consolidate multiple checks in different parts of the driver and can help MHI fail early on before power up begins if the offsets are not read correctly. Link: https://lore.kernel.org/r/1620330705-40192-2-git-send-email-bbhatt@codeaurora.org Reviewed-by: Jeffrey Hugo Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-4-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/init.c | 42 +++++++++++++++++++++++------------------- drivers/bus/mhi/core/pm.c | 28 ++++------------------------ 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index c81b377fca8f..11c7a3d3c9bf 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -1063,7 +1063,7 @@ EXPORT_SYMBOL_GPL(mhi_free_controller); int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) { struct device *dev = &mhi_cntrl->mhi_dev->dev; - u32 bhie_off; + u32 bhi_off, bhie_off; int ret; mutex_lock(&mhi_cntrl->pm_mutex); @@ -1072,29 +1072,36 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) if (ret) goto error_dev_ctxt; - /* - * Allocate RDDM table if specified, this table is for debugging purpose - */ - if (mhi_cntrl->rddm_size) { - mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image, - mhi_cntrl->rddm_size); + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &bhi_off); + if (ret) { + dev_err(dev, "Error getting BHI offset\n"); + goto error_reg_offset; + } + mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off; - /* - * This controller supports RDDM, so we need to manually clear - * BHIE RX registers since POR values are undefined. - */ + if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) { ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &bhie_off); if (ret) { dev_err(dev, "Error getting BHIE offset\n"); - goto bhie_error; + goto error_reg_offset; } - mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off; + } + + if (mhi_cntrl->rddm_size) { + /* + * This controller supports RDDM, so we need to manually clear + * BHIE RX registers since POR values are undefined. + */ memset_io(mhi_cntrl->bhie + BHIE_RXVECADDR_LOW_OFFS, 0, BHIE_RXVECSTATUS_OFFS - BHIE_RXVECADDR_LOW_OFFS + 4); - + /* + * Allocate RDDM table for debugging purpose if specified + */ + mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->rddm_image, + mhi_cntrl->rddm_size); if (mhi_cntrl->rddm_image) mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image); } @@ -1103,11 +1110,8 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) return 0; -bhie_error: - if (mhi_cntrl->rddm_image) { - mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->rddm_image); - mhi_cntrl->rddm_image = NULL; - } +error_reg_offset: + mhi_deinit_dev_ctxt(mhi_cntrl); error_dev_ctxt: mutex_unlock(&mhi_cntrl->pm_mutex); diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index bbf6cd04861e..ff7cdc8653ef 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1059,28 +1059,8 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (ret) goto error_setup_irq; - /* Setup BHI offset & INTVEC */ + /* Setup BHI INTVEC */ write_lock_irq(&mhi_cntrl->pm_lock); - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIOFF, &val); - if (ret) { - write_unlock_irq(&mhi_cntrl->pm_lock); - goto error_bhi_offset; - } - - mhi_cntrl->bhi = mhi_cntrl->regs + val; - - /* Setup BHIE offset */ - if (mhi_cntrl->fbc_download) { - ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, BHIEOFF, &val); - if (ret) { - write_unlock_irq(&mhi_cntrl->pm_lock); - dev_err(dev, "Error reading BHIE offset\n"); - goto error_bhi_offset; - } - - mhi_cntrl->bhie = mhi_cntrl->regs + val; - } - mhi_write_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_INTVEC, 0); mhi_cntrl->pm_state = MHI_PM_POR; mhi_cntrl->ee = MHI_EE_MAX; @@ -1091,7 +1071,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (!MHI_IN_PBL(current_ee) && current_ee != MHI_EE_AMSS) { dev_err(dev, "Not a valid EE for power on\n"); ret = -EIO; - goto error_bhi_offset; + goto error_async_power_up; } state = mhi_get_mhi_state(mhi_cntrl); @@ -1110,7 +1090,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) if (!ret) { ret = -EIO; dev_info(dev, "Failed to reset MHI due to syserr state\n"); - goto error_bhi_offset; + goto error_async_power_up; } /* @@ -1132,7 +1112,7 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) return 0; -error_bhi_offset: +error_async_power_up: mhi_deinit_free_irq(mhi_cntrl); error_setup_irq: -- cgit v1.2.3 From 3aa8f43b33687a1170e7b96f9b25037566e7fc04 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:49 +0530 Subject: bus: mhi: core: Set BHI and BHIe pointers to NULL in clean-up Set the BHI and BHIe pointers to NULL as part of clean-up. This makes sure that stale pointers are not accessed after powering MHI down. Link: https://lore.kernel.org/r/1620330705-40192-3-git-send-email-bbhatt@codeaurora.org Suggested-by: Hemant Kumar Reviewed-by: Jeffrey Hugo Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-5-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 11c7a3d3c9bf..1cc2f225d3d1 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -1132,6 +1132,9 @@ void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl) mhi_cntrl->rddm_image = NULL; } + mhi_cntrl->bhi = NULL; + mhi_cntrl->bhie = NULL; + mhi_deinit_dev_ctxt(mhi_cntrl); } EXPORT_SYMBOL_GPL(mhi_unprepare_after_power_down); -- cgit v1.2.3 From baa7a08569358d9d16e71ce36f287c39a665d776 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:50 +0530 Subject: bus: mhi: Add MMIO region length to controller structure Make controller driver specify the MMIO register region length for range checking of BHI or BHIe space. This can help validate that offsets are in acceptable memory region or not and avoid any boot-up issues due to BHI or BHIe memory accesses. Link: https://lore.kernel.org/r/1620330705-40192-4-git-send-email-bbhatt@codeaurora.org Reviewed-by: Jeffrey Hugo Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-6-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- include/linux/mhi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/mhi.h b/include/linux/mhi.h index 5e08468854db..b8ca6943f0b7 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -303,6 +303,7 @@ struct mhi_controller_config { * @rddm_size: RAM dump size that host should allocate for debugging purpose * @sbl_size: SBL image size downloaded through BHIe (optional) * @seg_len: BHIe vector size (optional) + * @reg_len: Length of the MHI MMIO region (required) * @fbc_image: Points to firmware image buffer * @rddm_image: Points to RAM dump buffer * @mhi_chan: Points to the channel configuration table @@ -386,6 +387,7 @@ struct mhi_controller { size_t rddm_size; size_t sbl_size; size_t seg_len; + size_t reg_len; struct image_info *fbc_image; struct image_info *rddm_image; struct mhi_chan *mhi_chan; -- cgit v1.2.3 From c92513b8814f4955c3ea3c685d9a193e1c7823f0 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:51 +0530 Subject: ath11k: set register access length for MHI driver MHI driver requires register space length to add range checks and prevent memory region accesses outside of that for MMIO space. Set it before registering the MHI controller. Link: https://lore.kernel.org/r/1620330705-40192-5-git-send-email-bbhatt@codeaurora.org Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Acked-by: Kalle Valo Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-7-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/net/wireless/ath/ath11k/mhi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 75cc2d80fde8..26c7ae242db6 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -330,6 +330,7 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) mhi_ctrl->cntrl_dev = ab->dev; mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; + mhi_ctrl->reg_len = ab->mem_len; ret = ath11k_mhi_get_msi(ab_pci); if (ret) { -- cgit v1.2.3 From 3551a30b9d4c2a5520e6c798758a6f4858adcd0a Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:52 +0530 Subject: bus: mhi: pci_generic: Set register access length for MHI driver MHI driver requires register space length to add range checks and prevent memory region accesses outside of that for MMIO space. Set it from the PCI generic controller driver before registering the MHI controller. Link: https://lore.kernel.org/r/1620330705-40192-6-git-send-email-bbhatt@codeaurora.org Reviewed-by: Hemant Kumar Reviewed-by: Loic Poulain Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-8-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/pci_generic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/bus/mhi/pci_generic.c b/drivers/bus/mhi/pci_generic.c index 5872c42927b1..4026d5c2ee79 100644 --- a/drivers/bus/mhi/pci_generic.c +++ b/drivers/bus/mhi/pci_generic.c @@ -524,6 +524,7 @@ static int mhi_pci_claim(struct mhi_controller *mhi_cntrl, return err; } mhi_cntrl->regs = pcim_iomap_table(pdev)[bar_num]; + mhi_cntrl->reg_len = pci_resource_len(pdev, bar_num); err = pci_set_dma_mask(pdev, dma_mask); if (err) { -- cgit v1.2.3 From 06e2c4a9eaf2a2ed267b9cee70f91aaf616eb925 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:53 +0530 Subject: bus: mhi: core: Add range checks for BHI and BHIe When obtaining the BHI or BHIe offsets during the power up preparation phase, range checks are missing. These can help controller drivers avoid accessing any address outside of the MMIO region. Ensure that mhi_cntrl->reg_len is set before MHI registration as it is a required field and range checks will fail without it. Link: https://lore.kernel.org/r/1620330705-40192-7-git-send-email-bbhatt@codeaurora.org Reviewed-by: Jeffrey Hugo Reviewed-by: Hemant Kumar Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-9-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/init.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index 1cc2f225d3d1..aeb1e3c2cdc4 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -885,7 +885,8 @@ int mhi_register_controller(struct mhi_controller *mhi_cntrl, if (!mhi_cntrl || !mhi_cntrl->cntrl_dev || !mhi_cntrl->regs || !mhi_cntrl->runtime_get || !mhi_cntrl->runtime_put || !mhi_cntrl->status_cb || !mhi_cntrl->read_reg || - !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || !mhi_cntrl->irq) + !mhi_cntrl->write_reg || !mhi_cntrl->nr_irqs || + !mhi_cntrl->irq || !mhi_cntrl->reg_len) return -EINVAL; ret = parse_config(mhi_cntrl, config); @@ -1077,6 +1078,13 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) dev_err(dev, "Error getting BHI offset\n"); goto error_reg_offset; } + + if (bhi_off >= mhi_cntrl->reg_len) { + dev_err(dev, "BHI offset: 0x%x is out of range: 0x%zx\n", + bhi_off, mhi_cntrl->reg_len); + ret = -EINVAL; + goto error_reg_offset; + } mhi_cntrl->bhi = mhi_cntrl->regs + bhi_off; if (mhi_cntrl->fbc_download || mhi_cntrl->rddm_size) { @@ -1086,6 +1094,14 @@ int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl) dev_err(dev, "Error getting BHIE offset\n"); goto error_reg_offset; } + + if (bhie_off >= mhi_cntrl->reg_len) { + dev_err(dev, + "BHIe offset: 0x%x is out of range: 0x%zx\n", + bhie_off, mhi_cntrl->reg_len); + ret = -EINVAL; + goto error_reg_offset; + } mhi_cntrl->bhie = mhi_cntrl->regs + bhie_off; } -- cgit v1.2.3 From 2e36190de69cb415955bfa8fbd94c44e38e58523 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:54 +0530 Subject: bus: mhi: core: Replace DMA allocation wrappers with original APIs There is nothing special done within the mhi_alloc_coherent() and the mhi_free_coherent() wrapper functions. They only directly call the equivalent DMA allocation functions. Replace them with the original function calls such that the implementation is clear and direct. Link: https://lore.kernel.org/r/1624392428-9328-1-git-send-email-bbhatt@codeaurora.org Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-10-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/boot.c | 17 +++++++++-------- drivers/bus/mhi/core/init.c | 32 ++++++++++++++++---------------- drivers/bus/mhi/core/internal.h | 20 -------------------- drivers/bus/mhi/core/main.c | 6 +++--- 4 files changed, 28 insertions(+), 47 deletions(-) diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c index 8100cf51cd09..0a972620a403 100644 --- a/drivers/bus/mhi/core/boot.c +++ b/drivers/bus/mhi/core/boot.c @@ -302,8 +302,8 @@ void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl, struct mhi_buf *mhi_buf = image_info->mhi_buf; for (i = 0; i < image_info->entries; i++, mhi_buf++) - mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf, - mhi_buf->dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + mhi_buf->buf, mhi_buf->dma_addr); kfree(image_info->mhi_buf); kfree(image_info); @@ -339,8 +339,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, vec_size = sizeof(struct bhi_vec_entry) * i; mhi_buf->len = vec_size; - mhi_buf->buf = mhi_alloc_coherent(mhi_cntrl, vec_size, - &mhi_buf->dma_addr, + mhi_buf->buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, + vec_size, &mhi_buf->dma_addr, GFP_KERNEL); if (!mhi_buf->buf) goto error_alloc_segment; @@ -354,8 +354,8 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, error_alloc_segment: for (--i, --mhi_buf; i >= 0; i--, mhi_buf--) - mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf, - mhi_buf->dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_buf->len, + mhi_buf->buf, mhi_buf->dma_addr); error_alloc_mhi_buf: kfree(img_info); @@ -442,7 +442,8 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) if (size > firmware->size) size = firmware->size; - buf = mhi_alloc_coherent(mhi_cntrl, size, &dma_addr, GFP_KERNEL); + buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, + GFP_KERNEL); if (!buf) { release_firmware(firmware); goto error_fw_load; @@ -451,7 +452,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) /* Download image using BHI */ memcpy(buf, firmware->data, size); ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); - mhi_free_coherent(mhi_cntrl, size, buf, dma_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); /* Error or in EDL mode, we're done */ if (ret) { diff --git a/drivers/bus/mhi/core/init.c b/drivers/bus/mhi/core/init.c index aeb1e3c2cdc4..5aaca6d0f52b 100644 --- a/drivers/bus/mhi/core/init.c +++ b/drivers/bus/mhi/core/init.c @@ -129,7 +129,7 @@ static int mhi_alloc_aligned_ring(struct mhi_controller *mhi_cntrl, u64 len) { ring->alloc_size = len + (len - 1); - ring->pre_aligned = mhi_alloc_coherent(mhi_cntrl, ring->alloc_size, + ring->pre_aligned = dma_alloc_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, &ring->dma_handle, GFP_KERNEL); if (!ring->pre_aligned) return -ENOMEM; @@ -221,13 +221,13 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl) mhi_cmd = mhi_cntrl->mhi_cmd; for (i = 0; i < NR_OF_CMD_RINGS; i++, mhi_cmd++) { ring = &mhi_cmd->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); ring->base = NULL; ring->iommu_base = 0; } - mhi_free_coherent(mhi_cntrl, + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr); @@ -237,17 +237,17 @@ void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl) continue; ring = &mhi_event->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); ring->base = NULL; ring->iommu_base = 0; } - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt, mhi_ctxt->er_ctxt_addr); - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt, mhi_ctxt->chan_ctxt_addr); @@ -275,7 +275,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) return -ENOMEM; /* Setup channel ctxt */ - mhi_ctxt->chan_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->chan_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, &mhi_ctxt->chan_ctxt_addr, @@ -307,7 +307,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) } /* Setup event context */ - mhi_ctxt->er_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->er_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, &mhi_ctxt->er_ctxt_addr, @@ -354,7 +354,7 @@ int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl) /* Setup cmd context */ ret = -ENOMEM; - mhi_ctxt->cmd_ctxt = mhi_alloc_coherent(mhi_cntrl, + mhi_ctxt->cmd_ctxt = dma_alloc_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, &mhi_ctxt->cmd_ctxt_addr, @@ -389,10 +389,10 @@ error_alloc_cmd: for (--i, --mhi_cmd; i >= 0; i--, mhi_cmd--) { struct mhi_ring *ring = &mhi_cmd->ring; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); } - mhi_free_coherent(mhi_cntrl, + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->cmd_ctxt) * NR_OF_CMD_RINGS, mhi_ctxt->cmd_ctxt, mhi_ctxt->cmd_ctxt_addr); i = mhi_cntrl->total_ev_rings; @@ -405,15 +405,15 @@ error_alloc_er: if (mhi_event->offload_ev) continue; - mhi_free_coherent(mhi_cntrl, ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, ring->alloc_size, ring->pre_aligned, ring->dma_handle); } - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->er_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->er_ctxt) * mhi_cntrl->total_ev_rings, mhi_ctxt->er_ctxt, mhi_ctxt->er_ctxt_addr); error_alloc_er_ctxt: - mhi_free_coherent(mhi_cntrl, sizeof(*mhi_ctxt->chan_ctxt) * + dma_free_coherent(mhi_cntrl->cntrl_dev, sizeof(*mhi_ctxt->chan_ctxt) * mhi_cntrl->max_chan, mhi_ctxt->chan_ctxt, mhi_ctxt->chan_ctxt_addr); @@ -567,7 +567,7 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, if (!chan_ctxt->rbase) /* Already uninitialized */ return; - mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size, tre_ring->pre_aligned, tre_ring->dma_handle); vfree(buf_ring->base); @@ -610,7 +610,7 @@ int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, buf_ring->base = vzalloc(buf_ring->len); if (!buf_ring->base) { - mhi_free_coherent(mhi_cntrl, tre_ring->alloc_size, + dma_free_coherent(mhi_cntrl->cntrl_dev, tre_ring->alloc_size, tre_ring->pre_aligned, tre_ring->dma_handle); return -ENOMEM; } diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index bc239a11aa69..721739c5e0d5 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -690,26 +690,6 @@ void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); -/* Memory allocation methods */ -static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl, - size_t size, - dma_addr_t *dma_handle, - gfp_t gfp) -{ - void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, dma_handle, - gfp); - - return buf; -} - -static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl, - size_t size, - void *vaddr, - dma_addr_t dma_handle) -{ - dma_free_coherent(mhi_cntrl->cntrl_dev, size, vaddr, dma_handle); -} - /* Event processing methods */ void mhi_ctrl_ev_task(unsigned long data); void mhi_ev_task(unsigned long data); diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 26bbc812121d..c01ec2fef02c 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -193,7 +193,7 @@ int mhi_map_single_no_bb(struct mhi_controller *mhi_cntrl, int mhi_map_single_use_bb(struct mhi_controller *mhi_cntrl, struct mhi_buf_info *buf_info) { - void *buf = mhi_alloc_coherent(mhi_cntrl, buf_info->len, + void *buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, buf_info->len, &buf_info->p_addr, GFP_ATOMIC); if (!buf) @@ -220,8 +220,8 @@ void mhi_unmap_single_use_bb(struct mhi_controller *mhi_cntrl, if (buf_info->dir == DMA_FROM_DEVICE) memcpy(buf_info->v_addr, buf_info->bb_addr, buf_info->len); - mhi_free_coherent(mhi_cntrl, buf_info->len, buf_info->bb_addr, - buf_info->p_addr); + dma_free_coherent(mhi_cntrl->cntrl_dev, buf_info->len, + buf_info->bb_addr, buf_info->p_addr); } static int get_nr_avail_ring_elements(struct mhi_controller *mhi_cntrl, -- cgit v1.2.3 From 61106bd2a8e4f02dacfbdf147c641b378a4c3de5 Mon Sep 17 00:00:00 2001 From: Bhaumik Bhatt Date: Mon, 2 Aug 2021 10:42:55 +0530 Subject: bus: mhi: core: Improve debug messages for power up Improve error message to be more descriptive if a failure occurs with an invalid power up execution environment. Additionally, add a debug log to print the execution environment and MHI state before a power up is attempted to confirm if the device is in an expected state. This helps clarify reasons for power up failures such as the device being found in a PBL or Emergency Download Mode execution environment and the host expected a full power up with Pass-Through and no image loading involved. Link: https://lore.kernel.org/r/1620072038-36160-1-git-send-email-bbhatt@codeaurora.org Reviewed-by: Hemant Kumar Reviewed-by: Jeffrey Hugo Reviewed-by: Manivannan Sadhasivam Signed-off-by: Bhaumik Bhatt Signed-off-by: Manivannan Sadhasivam Link: https://lore.kernel.org/r/20210802051255.5771-11-manivannan.sadhasivam@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/pm.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/bus/mhi/core/pm.c b/drivers/bus/mhi/core/pm.c index ff7cdc8653ef..fb99e3727155 100644 --- a/drivers/bus/mhi/core/pm.c +++ b/drivers/bus/mhi/core/pm.c @@ -1069,12 +1069,16 @@ int mhi_async_power_up(struct mhi_controller *mhi_cntrl) /* Confirm that the device is in valid exec env */ if (!MHI_IN_PBL(current_ee) && current_ee != MHI_EE_AMSS) { - dev_err(dev, "Not a valid EE for power on\n"); + dev_err(dev, "%s is not a valid EE for power on\n", + TO_MHI_EXEC_STR(current_ee)); ret = -EIO; goto error_async_power_up; } state = mhi_get_mhi_state(mhi_cntrl); + dev_dbg(dev, "Attempting power on with EE: %s, state: %s\n", + TO_MHI_EXEC_STR(current_ee), TO_MHI_STATE_STR(state)); + if (state == MHI_STATE_SYS_ERR) { mhi_set_mhi_state(mhi_cntrl, MHI_STATE_RESET); ret = wait_event_timeout(mhi_cntrl->state_event, -- cgit v1.2.3 From f9d8f4b3131cc84d3faf3210d9c22947fc53691d Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 2 Aug 2021 19:23:07 +0200 Subject: dt-bindings: misc: ge-achc: Convert to DT schema format Convert the binding to DT schema format. Also update the binding to fix shortcomings * Add "nxp,kinetis-k20" fallback compatible * add programming SPI interface and reset GPIO * add main clock * add voltage supplies * drop spi-max-frequency from required properties, driver will setup max. frequency Reviewed-by: Rob Herring Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210802172309.164365-2-sebastian.reichel@collabora.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/misc/ge-achc.txt | 26 --------- .../devicetree/bindings/misc/ge-achc.yaml | 65 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 26 deletions(-) delete mode 100644 Documentation/devicetree/bindings/misc/ge-achc.txt create mode 100644 Documentation/devicetree/bindings/misc/ge-achc.yaml diff --git a/Documentation/devicetree/bindings/misc/ge-achc.txt b/Documentation/devicetree/bindings/misc/ge-achc.txt deleted file mode 100644 index 77df94d7a32f..000000000000 --- a/Documentation/devicetree/bindings/misc/ge-achc.txt +++ /dev/null @@ -1,26 +0,0 @@ -* GE Healthcare USB Management Controller - -A device which handles data aquisition from compatible USB based peripherals. -SPI is used for device management. - -Note: This device does not expose the peripherals as USB devices. - -Required properties: - -- compatible : Should be "ge,achc" - -Required SPI properties: - -- reg : Should be address of the device chip select within - the controller. - -- spi-max-frequency : Maximum SPI clocking speed of device in Hz, should be - 1MHz for the GE ACHC. - -Example: - -spidev0: spi@0 { - compatible = "ge,achc"; - reg = <0>; - spi-max-frequency = <1000000>; -}; diff --git a/Documentation/devicetree/bindings/misc/ge-achc.yaml b/Documentation/devicetree/bindings/misc/ge-achc.yaml new file mode 100644 index 000000000000..ff07aa62ed57 --- /dev/null +++ b/Documentation/devicetree/bindings/misc/ge-achc.yaml @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +# Copyright (C) 2021 GE Inc. +# Copyright (C) 2021 Collabora Ltd. +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/misc/ge-achc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: GE Healthcare USB Management Controller + +description: | + A device which handles data acquisition from compatible USB based peripherals. + SPI is used for device management. + + Note: This device does not expose the peripherals as USB devices. + +maintainers: + - Sebastian Reichel + +properties: + compatible: + items: + - const: ge,achc + - const: nxp,kinetis-k20 + + clocks: + maxItems: 1 + + vdd-supply: + description: Digital power supply regulator on VDD pin + + vdda-supply: + description: Analog power supply regulator on VDDA pin + + reg: + items: + - description: Control interface + - description: Firmware programming interface + + reset-gpios: + description: GPIO used for hardware reset. + maxItems: 1 + +required: + - compatible + - clocks + - reg + - reset-gpios + +additionalProperties: false + +examples: + - | + #include + spi { + #address-cells = <1>; + #size-cells = <0>; + + spi@1 { + compatible = "ge,achc", "nxp,kinetis-k20"; + reg = <1>, <0>; + clocks = <&achc_24M>; + reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; + }; + }; -- cgit v1.2.3 From cd7cd5b716d594e27a933c12f026d4f2426d7bf4 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 2 Aug 2021 19:23:08 +0200 Subject: ARM: dts: imx53-ppd: Fix ACHC entry PPD has only one ACHC device, which effectively is a Kinetis microcontroller. It has one SPI interface used for normal communication. Additionally it's possible to flash the device firmware using NXP's EzPort protocol by correctly driving a second chip select pin and the device reset pin. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210802172309.164365-3-sebastian.reichel@collabora.com Signed-off-by: Greg Kroah-Hartman --- arch/arm/boot/dts/imx53-ppd.dts | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/imx53-ppd.dts b/arch/arm/boot/dts/imx53-ppd.dts index 5a5fa6190a52..37d0cffea99c 100644 --- a/arch/arm/boot/dts/imx53-ppd.dts +++ b/arch/arm/boot/dts/imx53-ppd.dts @@ -70,6 +70,12 @@ clock-frequency = <11289600>; }; + achc_24M: achc-clock { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24000000>; + }; + sgtlsound: sound { compatible = "fsl,imx53-cpuvo-sgtl5000", "fsl,imx-audio-sgtl5000"; @@ -314,16 +320,13 @@ &gpio4 12 GPIO_ACTIVE_LOW>; status = "okay"; - spidev0: spi@0 { - compatible = "ge,achc"; - reg = <0>; - spi-max-frequency = <1000000>; - }; - - spidev1: spi@1 { - compatible = "ge,achc"; - reg = <1>; - spi-max-frequency = <1000000>; + spidev0: spi@1 { + compatible = "ge,achc", "nxp,kinetis-k20"; + reg = <1>, <0>; + vdd-supply = <®_3v3>; + vdda-supply = <®_3v3>; + clocks = <&achc_24M>; + reset-gpios = <&gpio3 6 GPIO_ACTIVE_LOW>; }; gpioxra0: gpio@2 { -- cgit v1.2.3 From 0f920277dc22cb794f0572ee5d3423388453435d Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 2 Aug 2021 19:23:09 +0200 Subject: misc: gehc-achc: new driver General Electric Healthcare's PPD has a secondary processor from NXP's Kinetis K20 series. That device has two SPI chip selects: The main interface's behaviour depends on the loaded firmware and is currently unused. The secondary interface can be used to update the firmware using EzPort protocol. This is implemented by this driver using the kernel's firmware API. The firmware is being flashed into non-volatile flash memory, so it is enough to flash it once and not on every boot. Flashing will wear the flash memory (it has a life time of at least 10k programming cycles). At the same time only occasional FW updates are expected (like e.g. a BIOS update). Thus the firmware update is triggered via sysfs instead of doing it in the driver's probe routine like many other drivers. Signed-off-by: Sebastian Reichel Link: https://lore.kernel.org/r/20210802172309.164365-4-sebastian.reichel@collabora.com Signed-off-by: Greg Kroah-Hartman --- Documentation/ABI/testing/sysfs-driver-ge-achc | 15 + drivers/misc/Kconfig | 12 + drivers/misc/Makefile | 1 + drivers/misc/gehc-achc.c | 565 +++++++++++++++++++++++++ drivers/spi/spidev.c | 1 - 5 files changed, 593 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-driver-ge-achc create mode 100644 drivers/misc/gehc-achc.c diff --git a/Documentation/ABI/testing/sysfs-driver-ge-achc b/Documentation/ABI/testing/sysfs-driver-ge-achc new file mode 100644 index 000000000000..a9e7a079190c --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ge-achc @@ -0,0 +1,15 @@ +What: /sys/bus/spi//update_firmware +Date: Jul 2021 +Contact: sebastian.reichel@collabora.com +Description: Write 1 to this file to update the ACHC microcontroller + firmware via the EzPort interface. For this the kernel + will load "achc.bin" via the firmware API (so usually + from /lib/firmware). The write will block until the FW + has either been flashed successfully or an error occured. + +What: /sys/bus/spi//reset +Date: Jul 2021 +Contact: sebastian.reichel@collabora.com +Description: This file represents the microcontroller's reset line. + 1 means the reset line is asserted, 0 means it's not + asserted. The file is read and writable. diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index f4fb5c52b863..a420b59917db 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -208,6 +208,18 @@ config CS5535_CLOCK_EVENT_SRC MFGPTs have a better resolution and max interval than the generic PIT, and are suitable for use as high-res timers. +config GEHC_ACHC + tristate "GEHC ACHC support" + depends on SPI && SYSFS + depends on SOC_IMX53 || COMPILE_TEST + select FW_LOADER + help + Support for GE ACHC microcontroller, that is part of the GE + PPD device. + + To compile this driver as a module, choose M here: the + module will be called gehc-achc. + config HP_ILO tristate "Channel interface driver for the HP iLO processor" depends on PCI diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index e92a56d4442f..68b7b0736f16 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ obj-$(CONFIG_SGI_GRU) += sgi-gru/ obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o +obj-$(CONFIG_GEHC_ACHC) += gehc-achc.o obj-$(CONFIG_HP_ILO) += hpilo.o obj-$(CONFIG_APDS9802ALS) += apds9802als.o obj-$(CONFIG_ISL29003) += isl29003.o diff --git a/drivers/misc/gehc-achc.c b/drivers/misc/gehc-achc.c new file mode 100644 index 000000000000..891d9a214454 --- /dev/null +++ b/drivers/misc/gehc-achc.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * datasheet: https://www.nxp.com/docs/en/data-sheet/K20P144M120SF3.pdf + * + * Copyright (C) 2018-2021 Collabora + * Copyright (C) 2018-2021 GE Healthcare + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ACHC_MAX_FREQ_HZ 300000 +#define ACHC_FAST_READ_FREQ_HZ 1000000 + +struct achc_data { + struct spi_device *main; + struct spi_device *ezport; + struct gpio_desc *reset; + + struct mutex device_lock; /* avoid concurrent device access */ +}; + +#define EZPORT_RESET_DELAY_MS 100 +#define EZPORT_STARTUP_DELAY_MS 200 +#define EZPORT_WRITE_WAIT_MS 10 +#define EZPORT_TRANSFER_SIZE 2048 + +#define EZPORT_CMD_SP 0x02 /* flash section program */ +#define EZPORT_CMD_RDSR 0x05 /* read status register */ +#define EZPORT_CMD_WREN 0x06 /* write enable */ +#define EZPORT_CMD_FAST_READ 0x0b /* flash read data at high speed */ +#define EZPORT_CMD_RESET 0xb9 /* reset chip */ +#define EZPORT_CMD_BE 0xc7 /* bulk erase */ +#define EZPORT_CMD_SE 0xd8 /* sector erase */ + +#define EZPORT_SECTOR_SIZE 4096 +#define EZPORT_SECTOR_MASK (EZPORT_SECTOR_SIZE - 1) + +#define EZPORT_STATUS_WIP BIT(0) /* write in progress */ +#define EZPORT_STATUS_WEN BIT(1) /* write enable */ +#define EZPORT_STATUS_BEDIS BIT(2) /* bulk erase disable */ +#define EZPORT_STATUS_FLEXRAM BIT(3) /* FlexRAM mode */ +#define EZPORT_STATUS_WEF BIT(6) /* write error flag */ +#define EZPORT_STATUS_FS BIT(7) /* flash security */ + +static void ezport_reset(struct gpio_desc *reset) +{ + gpiod_set_value(reset, 1); + msleep(EZPORT_RESET_DELAY_MS); + gpiod_set_value(reset, 0); + msleep(EZPORT_STARTUP_DELAY_MS); +} + +static int ezport_start_programming(struct spi_device *spi, struct gpio_desc *reset) +{ + struct spi_message msg; + struct spi_transfer assert_cs = { + .cs_change = 1, + }; + struct spi_transfer release_cs = { }; + int ret; + + spi_bus_lock(spi->master); + + /* assert chip select */ + spi_message_init(&msg); + spi_message_add_tail(&assert_cs, &msg); + ret = spi_sync_locked(spi, &msg); + if (ret) + goto fail; + + msleep(EZPORT_STARTUP_DELAY_MS); + + /* reset with asserted chip select to switch into programming mode */ + ezport_reset(reset); + + /* release chip select */ + spi_message_init(&msg); + spi_message_add_tail(&release_cs, &msg); + ret = spi_sync_locked(spi, &msg); + +fail: + spi_bus_unlock(spi->master); + return ret; +} + +static void ezport_stop_programming(struct spi_device *spi, struct gpio_desc *reset) +{ + /* reset without asserted chip select to return into normal mode */ + spi_bus_lock(spi->master); + ezport_reset(reset); + spi_bus_unlock(spi->master); +} + +static int ezport_get_status_register(struct spi_device *spi) +{ + int ret; + + ret = spi_w8r8(spi, EZPORT_CMD_RDSR); + if (ret < 0) + return ret; + if (ret == 0xff) { + dev_err(&spi->dev, "Invalid EzPort status, EzPort is not functional!\n"); + return -EINVAL; + } + + return ret; +} + +static int ezport_soft_reset(struct spi_device *spi) +{ + u8 cmd = EZPORT_CMD_RESET; + int ret; + + ret = spi_write(spi, &cmd, 1); + if (ret < 0) + return ret; + + msleep(EZPORT_STARTUP_DELAY_MS); + + return 0; +} + +static int ezport_send_simple(struct spi_device *spi, u8 cmd) +{ + int ret; + + ret = spi_write(spi, &cmd, 1); + if (ret < 0) + return ret; + + return ezport_get_status_register(spi); +} + +static int ezport_wait_write(struct spi_device *spi, u32 retries) +{ + int ret; + u32 i; + + for (i = 0; i < retries; i++) { + ret = ezport_get_status_register(spi); + if (ret >= 0 && !(ret & EZPORT_STATUS_WIP)) + break; + msleep(EZPORT_WRITE_WAIT_MS); + } + + return ret; +} + +static int ezport_write_enable(struct spi_device *spi) +{ + int ret = 0, retries = 3; + + for (retries = 0; retries < 3; retries++) { + ret = ezport_send_simple(spi, EZPORT_CMD_WREN); + if (ret > 0 && ret & EZPORT_STATUS_WEN) + break; + } + + if (!(ret & EZPORT_STATUS_WEN)) { + dev_err(&spi->dev, "EzPort write enable timed out\n"); + return -ETIMEDOUT; + } + return 0; +} + +static int ezport_bulk_erase(struct spi_device *spi) +{ + int ret; + static const u8 cmd = EZPORT_CMD_BE; + + dev_dbg(&spi->dev, "EzPort bulk erase...\n"); + + ret = ezport_write_enable(spi); + if (ret < 0) + return ret; + + ret = spi_write(spi, &cmd, 1); + if (ret < 0) + return ret; + + ret = ezport_wait_write(spi, 1000); + if (ret < 0) + return ret; + + return 0; +} + +static int ezport_section_erase(struct spi_device *spi, u32 address) +{ + u8 query[] = {EZPORT_CMD_SE, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff}; + int ret; + + dev_dbg(&spi->dev, "Ezport section erase @ 0x%06x...\n", address); + + if (address & EZPORT_SECTOR_MASK) + return -EINVAL; + + ret = ezport_write_enable(spi); + if (ret < 0) + return ret; + + ret = spi_write(spi, query, sizeof(query)); + if (ret < 0) + return ret; + + return ezport_wait_write(spi, 200); +} + +static int ezport_flash_transfer(struct spi_device *spi, u32 address, + const u8 *payload, size_t payload_size) +{ + struct spi_transfer xfers[2] = {}; + u8 *command; + int ret; + + dev_dbg(&spi->dev, "EzPort write %zu bytes @ 0x%06x...\n", payload_size, address); + + ret = ezport_write_enable(spi); + if (ret < 0) + return ret; + + command = kmalloc(4, GFP_KERNEL | GFP_DMA); + if (!command) + return -ENOMEM; + + command[0] = EZPORT_CMD_SP; + command[1] = address >> 16; + command[2] = address >> 8; + command[3] = address >> 0; + + xfers[0].tx_buf = command; + xfers[0].len = 4; + + xfers[1].tx_buf = payload; + xfers[1].len = payload_size; + + ret = spi_sync_transfer(spi, xfers, 2); + kfree(command); + if (ret < 0) + return ret; + + return ezport_wait_write(spi, 40); +} + +static int ezport_flash_compare(struct spi_device *spi, u32 address, + const u8 *payload, size_t payload_size) +{ + struct spi_transfer xfers[2] = {}; + u8 *buffer; + int ret; + + buffer = kmalloc(payload_size + 5, GFP_KERNEL | GFP_DMA); + if (!buffer) + return -ENOMEM; + + buffer[0] = EZPORT_CMD_FAST_READ; + buffer[1] = address >> 16; + buffer[2] = address >> 8; + buffer[3] = address >> 0; + + xfers[0].tx_buf = buffer; + xfers[0].len = 4; + xfers[0].speed_hz = ACHC_FAST_READ_FREQ_HZ; + + xfers[1].rx_buf = buffer + 4; + xfers[1].len = payload_size + 1; + xfers[1].speed_hz = ACHC_FAST_READ_FREQ_HZ; + + ret = spi_sync_transfer(spi, xfers, 2); + if (ret) + goto err; + + /* FAST_READ receives one dummy byte before the real data */ + ret = memcmp(payload, buffer + 4 + 1, payload_size); + if (ret) { + ret = -EBADMSG; + dev_dbg(&spi->dev, "Verfication failure @ %06x", address); + print_hex_dump_bytes("fw: ", DUMP_PREFIX_OFFSET, payload, payload_size); + print_hex_dump_bytes("dev: ", DUMP_PREFIX_OFFSET, buffer + 4, payload_size); + } + +err: + kfree(buffer); + return ret; +} + +static int ezport_firmware_compare_data(struct spi_device *spi, + const u8 *data, size_t size) +{ + int ret; + size_t address = 0; + size_t transfer_size; + + dev_dbg(&spi->dev, "EzPort compare data with %zu bytes...\n", size); + + ret = ezport_get_status_register(spi); + if (ret < 0) + return ret; + + if (ret & EZPORT_STATUS_FS) { + dev_info(&spi->dev, "Device is in secure mode (status=0x%02x)!\n", ret); + dev_info(&spi->dev, "FW verification is not possible\n"); + return -EACCES; + } + + while (size - address > 0) { + transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address); + + ret = ezport_flash_compare(spi, address, data+address, transfer_size); + if (ret) + return ret; + + address += transfer_size; + } + + return 0; +} + +static int ezport_firmware_flash_data(struct spi_device *spi, + const u8 *data, size_t size) +{ + int ret; + size_t address = 0; + size_t transfer_size; + + dev_dbg(&spi->dev, "EzPort flash data with %zu bytes...\n", size); + + ret = ezport_get_status_register(spi); + if (ret < 0) + return ret; + + if (ret & EZPORT_STATUS_FS) { + ret = ezport_bulk_erase(spi); + if (ret < 0) + return ret; + if (ret & EZPORT_STATUS_FS) + return -EINVAL; + } + + while (size - address > 0) { + if (!(address & EZPORT_SECTOR_MASK)) { + ret = ezport_section_erase(spi, address); + if (ret < 0) + return ret; + if (ret & EZPORT_STATUS_WIP || ret & EZPORT_STATUS_WEF) + return -EIO; + } + + transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address); + + ret = ezport_flash_transfer(spi, address, + data+address, transfer_size); + if (ret < 0) + return ret; + else if (ret & EZPORT_STATUS_WIP) + return -ETIMEDOUT; + else if (ret & EZPORT_STATUS_WEF) + return -EIO; + + address += transfer_size; + } + + dev_dbg(&spi->dev, "EzPort verify flashed data...\n"); + ret = ezport_firmware_compare_data(spi, data, size); + + /* allow missing FW verfication in secure mode */ + if (ret == -EACCES) + ret = 0; + + if (ret < 0) + dev_err(&spi->dev, "Failed to verify flashed data: %d\n", ret); + + ret = ezport_soft_reset(spi); + if (ret < 0) + dev_warn(&spi->dev, "EzPort reset failed!\n"); + + return ret; +} + +static int ezport_firmware_load(struct spi_device *spi, const char *fwname) +{ + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, fwname, &spi->dev); + if (ret) { + dev_err(&spi->dev, "Could not get firmware: %d\n", ret); + return ret; + } + + ret = ezport_firmware_flash_data(spi, fw->data, fw->size); + + release_firmware(fw); + + return ret; +} + +/** + * ezport_flash - flash device firmware + * @spi: SPI device for NXP EzPort interface + * @reset: the gpio connected to the device reset pin + * @fwname: filename of the firmware that should be flashed + * + * Context: can sleep + * + * Return: 0 on success; negative errno on failure + */ +static int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname) +{ + int ret; + + ret = ezport_start_programming(spi, reset); + if (ret) + return ret; + + ret = ezport_firmware_load(spi, fwname); + + ezport_stop_programming(spi, reset); + + if (ret) + dev_err(&spi->dev, "Failed to flash firmware: %d\n", ret); + else + dev_dbg(&spi->dev, "Finished FW flashing!\n"); + + return ret; +} + +static ssize_t update_firmware_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct achc_data *achc = dev_get_drvdata(dev); + unsigned long value; + int ret; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0 || value != 1) + return -EINVAL; + + mutex_lock(&achc->device_lock); + ret = ezport_flash(achc->ezport, achc->reset, "achc.bin"); + mutex_unlock(&achc->device_lock); + + if (ret < 0) + return ret; + + return count; +} +static DEVICE_ATTR_WO(update_firmware); + +static ssize_t reset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct achc_data *achc = dev_get_drvdata(dev); + int ret; + + mutex_lock(&achc->device_lock); + ret = gpiod_get_value(achc->reset); + mutex_unlock(&achc->device_lock); + + if (ret < 0) + return ret; + + return sysfs_emit(buf, "%d\n", ret); +} + +static ssize_t reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct achc_data *achc = dev_get_drvdata(dev); + unsigned long value; + int ret; + + ret = kstrtoul(buf, 0, &value); + if (ret < 0 || value > 1) + return -EINVAL; + + mutex_lock(&achc->device_lock); + gpiod_set_value(achc->reset, value); + mutex_unlock(&achc->device_lock); + + return count; +} +static DEVICE_ATTR_RW(reset); + +static struct attribute *gehc_achc_attrs[] = { + &dev_attr_update_firmware.attr, + &dev_attr_reset.attr, + NULL, +}; +ATTRIBUTE_GROUPS(gehc_achc); + +static void unregister_ezport(void *data) +{ + struct spi_device *ezport = data; + + spi_unregister_device(ezport); +} + +static int gehc_achc_probe(struct spi_device *spi) +{ + struct achc_data *achc; + int ezport_reg, ret; + + spi->max_speed_hz = ACHC_MAX_FREQ_HZ; + spi->bits_per_word = 8; + spi->mode = SPI_MODE_0; + + achc = devm_kzalloc(&spi->dev, sizeof(*achc), GFP_KERNEL); + if (!achc) + return -ENOMEM; + spi_set_drvdata(spi, achc); + achc->main = spi; + + mutex_init(&achc->device_lock); + + ret = of_property_read_u32_index(spi->dev.of_node, "reg", 1, &ezport_reg); + if (ret) + return dev_err_probe(&spi->dev, ret, "missing second reg entry!\n"); + + achc->ezport = spi_new_ancillary_device(spi, ezport_reg); + if (IS_ERR(achc->ezport)) + return PTR_ERR(achc->ezport); + + ret = devm_add_action_or_reset(&spi->dev, unregister_ezport, achc->ezport); + if (ret) + return ret; + + achc->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(achc->reset)) + return dev_err_probe(&spi->dev, PTR_ERR(achc->reset), "Could not get reset gpio\n"); + + return 0; +} + +static const struct spi_device_id gehc_achc_id[] = { + { "ge,achc", 0 }, + { } +}; +MODULE_DEVICE_TABLE(spi, gehc_achc_id); + +static const struct of_device_id gehc_achc_of_match[] = { + { .compatible = "ge,achc" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, gehc_achc_of_match); + +static struct spi_driver gehc_achc_spi_driver = { + .driver = { + .name = "gehc-achc", + .of_match_table = gehc_achc_of_match, + .dev_groups = gehc_achc_groups, + }, + .probe = gehc_achc_probe, + .id_table = gehc_achc_id, +}; +module_spi_driver(gehc_achc_spi_driver); + +MODULE_DESCRIPTION("GEHC ACHC driver"); +MODULE_AUTHOR("Sebastian Reichel "); +MODULE_LICENSE("GPL"); diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 24e9469ea35b..6dc29ce3b4bf 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -677,7 +677,6 @@ static struct class *spidev_class; static const struct of_device_id spidev_dt_ids[] = { { .compatible = "rohm,dh2228fv" }, { .compatible = "lineartechnology,ltc2488" }, - { .compatible = "ge,achc" }, { .compatible = "semtech,sx1301" }, { .compatible = "lwn,bk4" }, { .compatible = "dh,dhcom-board" }, -- cgit v1.2.3 From 1716e49eb8b4478e8952ce9206f1974c3e842e1f Mon Sep 17 00:00:00 2001 From: kernel test robot Date: Wed, 23 Jun 2021 16:23:30 +0200 Subject: phy: rockchip-inno-usb2: fix for_each_child.cocci warnings For_each_available_child_of_node should have of_node_put() before break around line 1184. The other jumps out of the loop do contain the put. Generated by: scripts/coccinelle/iterators/for_each_child.cocci CC: Sumera Priyadarsini Reported-by: kernel test robot Signed-off-by: kernel test robot Signed-off-by: Julia Lawall Link: https://lore.kernel.org/r/alpine.DEB.2.22.394.2106231617540.99238@hadrien Signed-off-by: Vinod Koul --- drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index beacac1dd253..4f569d9307b9 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -1180,8 +1180,10 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev) next_child: /* to prevent out of boundary */ - if (++index >= rphy->phy_cfg->num_ports) + if (++index >= rphy->phy_cfg->num_ports) { + of_node_put(child_np); break; + } } provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); -- cgit v1.2.3 From 88d8175ad8badc74d0d53308dbbbf65b1eb0cebb Mon Sep 17 00:00:00 2001 From: Dong Aisheng Date: Thu, 15 Jul 2021 16:25:33 +0800 Subject: dt-bindings: phy: imx8mq-usb-phy: convert to json schema Convert to jason schema. Cc: Kishon Vijay Abraham I Cc: Vinod Koul Cc: Rob Herring Cc: Li Jun Cc: linux-phy@lists.infradead.org Signed-off-by: Dong Aisheng Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210715082536.1882077-5-aisheng.dong@nxp.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt | 20 -------- .../bindings/phy/fsl,imx8mq-usb-phy.yaml | 53 ++++++++++++++++++++++ 2 files changed, 53 insertions(+), 20 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt create mode 100644 Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt deleted file mode 100644 index 7c70f2ad9942..000000000000 --- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt +++ /dev/null @@ -1,20 +0,0 @@ -* Freescale i.MX8MQ USB3 PHY binding - -Required properties: -- compatible: Should be "fsl,imx8mq-usb-phy" or "fsl,imx8mp-usb-phy" -- #phys-cells: must be 0 (see phy-bindings.txt in this directory) -- reg: The base address and length of the registers -- clocks: phandles to the clocks for each clock listed in clock-names -- clock-names: must contain "phy" - -Optional properties: -- vbus-supply: A phandle to the regulator for USB VBUS. - -Example: - usb3_phy0: phy@381f0040 { - compatible = "fsl,imx8mq-usb-phy"; - reg = <0x381f0040 0x40>; - clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>; - clock-names = "phy"; - #phy-cells = <0>; - }; diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml new file mode 100644 index 000000000000..2936f3510a6a --- /dev/null +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/fsl,imx8mq-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Freescale i.MX8MQ USB3 PHY binding + +maintainers: + - Li Jun + +properties: + compatible: + enum: + - fsl,imx8mq-usb-phy + - fsl,imx8mp-usb-phy + + reg: + maxItems: 1 + + "#phy-cells": + const: 0 + + clocks: + maxItems: 1 + + clock-names: + items: + - const: phy + + vbus-supply: + description: + A phandle to the regulator for USB VBUS. + +required: + - compatible + - reg + - "#phy-cells" + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + usb3_phy0: phy@381f0040 { + compatible = "fsl,imx8mq-usb-phy"; + reg = <0x381f0040 0x40>; + clocks = <&clk IMX8MQ_CLK_USB1_PHY_ROOT>; + clock-names = "phy"; + #phy-cells = <0>; + }; -- cgit v1.2.3 From 07e97f744c3bb9249e72e634f713d665436ffd72 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 22 Jul 2021 19:25:48 -0700 Subject: phy: qualcomm: phy-qcom-usb-hs: repair non-kernel-doc comment Fix errant use of "/**" to begin a comment although the comment is not kernel-doc notation. Just use "/*" instead. Fixes this kernel-doc warning: drivers/phy/qualcomm/phy-qcom-usb-hs.c:3: warning: This comment starts with '/**', but isn't a kernel-doc comment. Refer Documentation/doc-guide/kernel-doc.rst * Copyright (C) 2016 Linaro Ltd Signed-off-by: Randy Dunlap Reported-by: kernel test robot Cc: Andy Gross Cc: Bjorn Andersson Cc: linux-arm-msm@vger.kernel.org Cc: Kishon Vijay Abraham I Cc: Vinod Koul Cc: linux-phy@lists.infradead.org Link: https://lore.kernel.org/r/20210723022548.25695-1-rdunlap@infradead.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-usb-hs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/phy/qualcomm/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c index 5c6c17673396..53e46c220a3a 100644 --- a/drivers/phy/qualcomm/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * Copyright (C) 2016 Linaro Ltd */ #include -- cgit v1.2.3 From c52c90dbcb8c2676dab22cb21c0f0c5da527dfd3 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 23 Jul 2021 16:22:40 +0800 Subject: dt-bindings: phy: mediatek: tphy: add support hardware version 3 The PHYA architecture is updated, and doesn't support slew rate calibration anymore on 7nm or advanced process, add a new version number to support it. Due to the FreqMeter bank is not used but reserved, it's backward with v2 until now. For mt8195, no function changes when use generic v2 or v3 compatible, but prefer to use v3's compatible, it will not waste the time to calibrate the slew rate, and also correspond with hardware version. Acked-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1627028562-23584-1-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index ef9d9d4e6875..838852cb8527 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -15,7 +15,7 @@ description: | controllers on MediaTek SoCs, includes USB2.0, USB3.0, PCIe and SATA. Layout differences of banks between T-PHY V1 (mt8173/mt2701) and - T-PHY V2 (mt2712) when works on USB mode: + T-PHY V2 (mt2712) / V3 (mt8195) when works on USB mode: ----------------------------------- Version 1: port offset bank @@ -34,7 +34,7 @@ description: | u2 port2 0x1800 U2PHY_COM ... - Version 2: + Version 2/3: port offset bank u2 port0 0x0000 MISC 0x0100 FMREG @@ -59,7 +59,8 @@ description: | SPLLC shared by u3 ports and FMREG shared by u2 ports on V1 are put back into each port; a new bank MISC for u2 ports and CHIP for u3 ports are - added on V2. + added on V2; the FMREG bank for slew rate calibration is not used anymore + and reserved on V3; properties: $nodename: @@ -79,8 +80,11 @@ properties: - mediatek,mt2712-tphy - mediatek,mt7629-tphy - mediatek,mt8183-tphy - - mediatek,mt8195-tphy - const: mediatek,generic-tphy-v2 + - items: + - enum: + - mediatek,mt8195-tphy + - const: mediatek,generic-tphy-v3 - const: mediatek,mt2701-u3phy deprecated: true - const: mediatek,mt2712-u3phy @@ -91,7 +95,7 @@ properties: description: Register shared by multiple ports, exclude port's private register. It is needed for T-PHY V1, such as mt2701 and mt8173, but not for - T-PHY V2, such as mt2712. + T-PHY V2/V3, such as mt2712. maxItems: 1 "#address-cells": -- cgit v1.2.3 From 27974e6208c0c44f89e76fc65ad67f9bc1c279a6 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 23 Jul 2021 16:22:41 +0800 Subject: phy: phy-mtk-tphy: support new hardware version The PHYA arch is updated, and doesn't support slew rate calibrate anymore on 7nm or advanced process, add a new version number to support it. Note: the FreqMeter bank is not used but reserved. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1627028562-23584-2-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 40 +++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 731c483a04de..42a1174da6cc 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -27,7 +27,8 @@ #define SSUSB_SIFSLV_V1_U3PHYD 0x000 #define SSUSB_SIFSLV_V1_U3PHYA 0x200 -/* version V2 sub-banks offset base address */ +/* version V2/V3 sub-banks offset base address */ +/* V3: U2FREQ is not used anymore, but reserved */ /* u2 phy banks */ #define SSUSB_SIFSLV_V2_MISC 0x000 #define SSUSB_SIFSLV_V2_U2FREQ 0x100 @@ -270,6 +271,7 @@ enum mtk_phy_version { MTK_PHY_V1 = 1, MTK_PHY_V2, + MTK_PHY_V3, }; struct mtk_phy_pdata { @@ -330,6 +332,10 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, int fm_out; u32 tmp; + /* HW V3 doesn't support slew rate cal anymore */ + if (tphy->pdata->version == MTK_PHY_V3) + return; + /* use force value */ if (instance->eye_src) return; @@ -878,7 +884,7 @@ static void u2_phy_props_set(struct mtk_tphy *tphy, writel(tmp, com + U3P_U2PHYBC12C); } - if (instance->eye_src) { + if (tphy->pdata->version < MTK_PHY_V3 && instance->eye_src) { tmp = readl(com + U3P_USBPHYACR5); tmp &= ~PA5_RG_U2_HSTX_SRCTRL; tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src); @@ -1042,11 +1048,15 @@ static struct phy *mtk_phy_xlate(struct device *dev, return ERR_PTR(-EINVAL); } - if (tphy->pdata->version == MTK_PHY_V1) { + switch (tphy->pdata->version) { + case MTK_PHY_V1: phy_v1_banks_init(tphy, instance); - } else if (tphy->pdata->version == MTK_PHY_V2) { + break; + case MTK_PHY_V2: + case MTK_PHY_V3: phy_v2_banks_init(tphy, instance); - } else { + break; + default: dev_err(dev, "phy version is not supported\n"); return ERR_PTR(-EINVAL); } @@ -1075,6 +1085,10 @@ static const struct mtk_phy_pdata tphy_v2_pdata = { .version = MTK_PHY_V2, }; +static const struct mtk_phy_pdata tphy_v3_pdata = { + .version = MTK_PHY_V3, +}; + static const struct mtk_phy_pdata mt8173_pdata = { .avoid_rx_sen_degradation = true, .version = MTK_PHY_V1, @@ -1086,6 +1100,7 @@ static const struct of_device_id mtk_tphy_id_table[] = { { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, { .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata }, { .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata }, + { .compatible = "mediatek,generic-tphy-v3", .data = &tphy_v3_pdata }, { }, }; MODULE_DEVICE_TABLE(of, mtk_tphy_id_table); @@ -1129,12 +1144,15 @@ static int mtk_tphy_probe(struct platform_device *pdev) } } - tphy->src_ref_clk = U3P_REF_CLK; - tphy->src_coef = U3P_SLEW_RATE_COEF; - /* update parameters of slew rate calibrate if exist */ - device_property_read_u32(dev, "mediatek,src-ref-clk-mhz", - &tphy->src_ref_clk); - device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef); + if (tphy->pdata->version < MTK_PHY_V3) { + tphy->src_ref_clk = U3P_REF_CLK; + tphy->src_coef = U3P_SLEW_RATE_COEF; + /* update parameters of slew rate calibrate if exist */ + device_property_read_u32(dev, "mediatek,src-ref-clk-mhz", + &tphy->src_ref_clk); + device_property_read_u32(dev, "mediatek,src-coef", + &tphy->src_coef); + } port = 0; for_each_child_of_node(np, child_np) { -- cgit v1.2.3 From a69f29cb50a0069f3442c08fcf21fad55d48f4d2 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Fri, 23 Jul 2021 16:22:42 +0800 Subject: phy: phy-mtk-tphy: add support mt8195 The controller is designed to use use PLL integer mode, but in fact used fractional mode for some ones on mt8195, this causes signal degradation (e.g. eye diagram test fail), fix it by switching PLL to 26Mhz from default 48Mhz to improve signal quality. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1627028562-23584-3-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 42a1174da6cc..33000b38fd1b 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -41,6 +41,8 @@ #define U3P_USBPHYACR0 0x000 #define PA0_RG_U2PLL_FORCE_ON BIT(15) +#define PA0_USB20_PLL_PREDIV GENMASK(7, 6) +#define PA0_USB20_PLL_PREDIV_VAL(x) ((0x3 & (x)) << 6) #define PA0_RG_USB20_INTR_EN BIT(5) #define U3P_USBPHYACR1 0x004 @@ -52,6 +54,8 @@ #define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8) #define U3P_USBPHYACR2 0x008 +#define PA2_RG_U2PLL_BW GENMASK(21, 19) +#define PA2_RG_U2PLL_BW_VAL(x) ((0x7 & (x)) << 19) #define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18) #define U3P_USBPHYACR5 0x014 @@ -73,6 +77,14 @@ #define P2C_USB20_GPIO_MODE BIT(8) #define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE) +#define U3P_U2PHYA_RESV 0x030 +#define P2R_RG_U2PLL_FBDIV_26M 0x1bb13b +#define P2R_RG_U2PLL_FBDIV_48M 0x3c0000 + +#define U3P_U2PHYA_RESV1 0x044 +#define P2R_RG_U2PLL_REFCLK_SEL BIT(5) +#define P2R_RG_U2PLL_FRA_EN BIT(3) + #define U3D_U2PHYDCR0 0x060 #define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24) @@ -277,6 +289,12 @@ enum mtk_phy_version { struct mtk_phy_pdata { /* avoid RX sensitivity level degradation only for mt8173 */ bool avoid_rx_sen_degradation; + /* + * workaround only for mt8195, HW fix it for others of V3, + * u2phy should use integer mode instead of fractional mode of + * 48M PLL, fix it by switching PLL to 26M from default 48M + */ + bool sw_pll_48m_to_26m; enum mtk_phy_version version; }; @@ -456,6 +474,33 @@ static void u3_phy_instance_init(struct mtk_tphy *tphy, dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); } +static void u2_phy_pll_26m_set(struct mtk_tphy *tphy, + struct mtk_phy_instance *instance) +{ + struct u2phy_banks *u2_banks = &instance->u2_banks; + void __iomem *com = u2_banks->com; + u32 tmp; + + if (!tphy->pdata->sw_pll_48m_to_26m) + return; + + tmp = readl(com + U3P_USBPHYACR0); + tmp &= ~PA0_USB20_PLL_PREDIV; + tmp |= PA0_USB20_PLL_PREDIV_VAL(0); + writel(tmp, com + U3P_USBPHYACR0); + + tmp = readl(com + U3P_USBPHYACR2); + tmp &= ~PA2_RG_U2PLL_BW; + tmp |= PA2_RG_U2PLL_BW_VAL(3); + writel(tmp, com + U3P_USBPHYACR2); + + writel(P2R_RG_U2PLL_FBDIV_26M, com + U3P_U2PHYA_RESV); + + tmp = readl(com + U3P_U2PHYA_RESV1); + tmp |= P2R_RG_U2PLL_FRA_EN | P2R_RG_U2PLL_REFCLK_SEL; + writel(tmp, com + U3P_U2PHYA_RESV1); +} + static void u2_phy_instance_init(struct mtk_tphy *tphy, struct mtk_phy_instance *instance) { @@ -515,6 +560,9 @@ static void u2_phy_instance_init(struct mtk_tphy *tphy, tmp |= PA6_RG_U2_SQTH_VAL(2); writel(tmp, com + U3P_USBPHYACR6); + /* Workaround only for mt8195, HW fix it for others (V3) */ + u2_phy_pll_26m_set(tphy, instance); + dev_dbg(tphy->dev, "%s(%d)\n", __func__, index); } @@ -1094,10 +1142,16 @@ static const struct mtk_phy_pdata mt8173_pdata = { .version = MTK_PHY_V1, }; +static const struct mtk_phy_pdata mt8195_pdata = { + .sw_pll_48m_to_26m = true, + .version = MTK_PHY_V3, +}; + static const struct of_device_id mtk_tphy_id_table[] = { { .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata }, { .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata }, { .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, + { .compatible = "mediatek,mt8195-tphy", .data = &mt8195_pdata }, { .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata }, { .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata }, { .compatible = "mediatek,generic-tphy-v3", .data = &tphy_v3_pdata }, -- cgit v1.2.3 From 7481f91f1d7e8a004f19b55747d38a934119abe2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 27 Jul 2021 13:45:12 +0300 Subject: phy: phy-twl4030-usb: Disable PHY for suspend Since commit 88d26136a256 ("PM: Prevent runtime suspend during system resume"), PM runtime will not let devices idle during system suspend. This is because of the pm_runtime_get_noresume() call done in device_prepare() that is not released until at device_complete() after resume. We must now disable the USB PHY in suspend if no USB cable is connected. Cc: Andreas Kemnade Signed-off-by: Tony Lindgren Link: https://lore.kernel.org/r/20210727104512.52968-1-tony@atomide.com Signed-off-by: Vinod Koul --- drivers/phy/ti/phy-twl4030-usb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 5771e2486a3b..ac71017a0bc1 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -162,6 +162,8 @@ struct twl4030_usb { atomic_t connected; bool vbus_supplied; bool musb_mailbox_pending; + unsigned long runtime_suspended:1; + unsigned long needs_resume:1; struct delayed_work id_workaround_work; }; @@ -384,6 +386,9 @@ static void __twl4030_phy_power(struct twl4030_usb *twl, int on) WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); } +static int twl4030_usb_runtime_suspend(struct device *dev); +static int twl4030_usb_runtime_resume(struct device *dev); + static int __maybe_unused twl4030_usb_suspend(struct device *dev) { struct twl4030_usb *twl = dev_get_drvdata(dev); @@ -395,6 +400,10 @@ static int __maybe_unused twl4030_usb_suspend(struct device *dev) */ dev_dbg(twl->dev, "%s\n", __func__); disable_irq(twl->irq); + if (!twl->runtime_suspended && !atomic_read(&twl->connected)) { + twl4030_usb_runtime_suspend(dev); + twl->needs_resume = 1; + } return 0; } @@ -405,9 +414,13 @@ static int __maybe_unused twl4030_usb_resume(struct device *dev) dev_dbg(twl->dev, "%s\n", __func__); enable_irq(twl->irq); + if (twl->needs_resume) + twl4030_usb_runtime_resume(dev); /* check whether cable status changed */ twl4030_usb_irq(0, twl); + twl->runtime_suspended = 0; + return 0; } @@ -422,6 +435,8 @@ static int __maybe_unused twl4030_usb_runtime_suspend(struct device *dev) regulator_disable(twl->usb1v8); regulator_disable(twl->usb3v1); + twl->runtime_suspended = 1; + return 0; } -- cgit v1.2.3 From 1a00d130596f863243b1a0aa527dd66ecee70065 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 21 Jul 2021 15:56:29 -0700 Subject: dt-bindings: phy: qcom,qmp-usb3-dp: Add support for sc8180x The SC8180x has two instances of the QMP USB/DP combo PHYs, add a compatible for these. Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210721225630.3035861-1-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml index 217aa6c91893..1d49cc3d4eae 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-usb3-dp-phy.yaml @@ -14,6 +14,7 @@ properties: compatible: enum: - qcom,sc7180-qmp-usb3-dp-phy + - qcom,sc8180x-qmp-usb3-dp-phy - qcom,sdm845-qmp-usb3-dp-phy - qcom,sm8250-qmp-usb3-dp-phy reg: -- cgit v1.2.3 From 1633802cd4ac338554ec94cd4d46ac5ef322aa49 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 21 Jul 2021 15:56:30 -0700 Subject: phy: qcom: qmp: Add SC8180x USB/DP combo The two USB QMPs are USB/DP compbo PHYs, add the compatible for this combination to allow DP output. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210721225630.3035861-2-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 47 +++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 2195f8ac393b..5e302830d061 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -3536,6 +3536,46 @@ static const struct qmp_phy_cfg sc8180x_pciephy_cfg = { .pwrdn_delay_max = 1005, /* us */ }; +static const struct qmp_phy_cfg sc8180x_dpphy_cfg = { + .type = PHY_TYPE_DP, + .nlanes = 1, + + .serdes_tbl = qmp_v4_dp_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl), + .tx_tbl = qmp_v4_dp_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(qmp_v4_dp_tx_tbl), + + .serdes_tbl_rbr = qmp_v4_dp_serdes_tbl_rbr, + .serdes_tbl_rbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_rbr), + .serdes_tbl_hbr = qmp_v4_dp_serdes_tbl_hbr, + .serdes_tbl_hbr_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr), + .serdes_tbl_hbr2 = qmp_v4_dp_serdes_tbl_hbr2, + .serdes_tbl_hbr2_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr2), + .serdes_tbl_hbr3 = qmp_v4_dp_serdes_tbl_hbr3, + .serdes_tbl_hbr3_num = ARRAY_SIZE(qmp_v4_dp_serdes_tbl_hbr3), + + .clk_list = qmp_v3_phy_clk_l, + .num_clks = ARRAY_SIZE(qmp_v3_phy_clk_l), + .reset_list = sc7180_usb3phy_reset_l, + .num_resets = ARRAY_SIZE(sc7180_usb3phy_reset_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = qmp_v3_usb3phy_regs_layout, + + .has_phy_dp_com_ctrl = true, + .is_dual_lane_phy = true, + + .dp_aux_init = qcom_qmp_v4_phy_dp_aux_init, + .configure_dp_tx = qcom_qmp_v4_phy_configure_dp_tx, + .configure_dp_phy = qcom_qmp_v4_phy_configure_dp_phy, + .calibrate_dp_phy = qcom_qmp_v4_dp_phy_calibrate, +}; + +static const struct qmp_phy_combo_cfg sc8180x_usb3dpphy_cfg = { + .usb_cfg = &sm8150_usb3phy_cfg, + .dp_cfg = &sc8180x_dpphy_cfg, +}; + static const struct qmp_phy_cfg sm8150_usb3_uniphy_cfg = { .type = PHY_TYPE_USB3, .nlanes = 1, @@ -5377,6 +5417,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,sc8180x-qmp-usb3-phy", .data = &sm8150_usb3phy_cfg, + }, { + .compatible = "qcom,sc8180x-qmp-usb3-dp-phy", + /* It's a combo phy */ }, { .compatible = "qcom,sdm845-qhp-pcie-phy", .data = &sdm845_qhp_pciephy_cfg, @@ -5454,6 +5497,10 @@ static const struct of_device_id qcom_qmp_combo_phy_of_match_table[] = { .compatible = "qcom,sm8250-qmp-usb3-dp-phy", .data = &sm8250_usb3dpphy_cfg, }, + { + .compatible = "qcom,sc8180x-qmp-usb3-dp-phy", + .data = &sc8180x_usb3dpphy_cfg, + }, { } }; -- cgit v1.2.3 From b70ee49c98d0e550b324afe869d3d17fec6190f5 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 23 Jul 2021 19:26:05 +0530 Subject: dt-bindings: phy: Convert AM654 SERDES bindings to YAML Convert SERDES dt-bindings for TI's AM654 SoC to YAML binding. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210723135605.23572-1-kishon@ti.com Signed-off-by: Vinod Koul --- .../bindings/phy/ti,phy-am654-serdes.txt | 82 ---------------- .../bindings/phy/ti,phy-am654-serdes.yaml | 103 +++++++++++++++++++++ 2 files changed, 103 insertions(+), 82 deletions(-) delete mode 100644 Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt create mode 100644 Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml diff --git a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt deleted file mode 100644 index 64b286d2d398..000000000000 --- a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt +++ /dev/null @@ -1,82 +0,0 @@ -TI AM654 SERDES - -Required properties: - - compatible: Should be "ti,phy-am654-serdes" - - reg : Address and length of the register set for the device. - - #phy-cells: determine the number of cells that should be given in the - phandle while referencing this phy. Should be "2". The 1st cell - corresponds to the phy type (should be one of the types specified in - include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes - lane function. - If SERDES0 is referenced 2nd cell should be: - 0 - USB3 - 1 - PCIe0 Lane0 - 2 - ICSS2 SGMII Lane0 - If SERDES1 is referenced 2nd cell should be: - 0 - PCIe1 Lane0 - 1 - PCIe0 Lane1 - 2 - ICSS2 SGMII Lane1 - - power-domains: As documented by the generic PM domain bindings in - Documentation/devicetree/bindings/power/power_domain.txt. - - clocks: List of clock-specifiers representing the input to the SERDES. - Should have 3 items representing the left input clock, external - reference clock and right input clock in that order. - - clock-output-names: List of clock names for each of the clock outputs of - SERDES. Should have 3 items for CMU reference clock, - left output clock and right output clock in that order. - - assigned-clocks: As defined in - Documentation/devicetree/bindings/clock/clock-bindings.txt - - assigned-clock-parents: As defined in - Documentation/devicetree/bindings/clock/clock-bindings.txt - - #clock-cells: Should be <1> to choose between the 3 output clocks. - Defined in Documentation/devicetree/bindings/clock/clock-bindings.txt - - The following macros are defined in dt-bindings/phy/phy-am654-serdes.h - for selecting the correct reference clock. This can be used while - specifying the clocks created by SERDES. - => AM654_SERDES_CMU_REFCLK - => AM654_SERDES_LO_REFCLK - => AM654_SERDES_RO_REFCLK - - - mux-controls: Phandle to the multiplexer that is used to select the lane - function. See #phy-cells above to see the multiplex values. - -Example: - -Example for SERDES0 is given below. It has 3 clock inputs; -left input reference clock as indicated by <&k3_clks 153 4>, external -reference clock as indicated by <&k3_clks 153 1> and right input -reference clock as indicated by <&serdes1 AM654_SERDES_LO_REFCLK>. (The -right input of SERDES0 is connected to the left output of SERDES1). - -SERDES0 registers 3 clock outputs as indicated in clock-output-names. The -first refers to the CMU reference clock, second refers to the left output -reference clock and the third refers to the right output reference clock. - -The assigned-clocks and assigned-clock-parents is used here to set the -parent of left input reference clock to MAINHSDIV_CLKOUT4 and parent of -CMU reference clock to left input reference clock. - -serdes0: serdes@900000 { - compatible = "ti,phy-am654-serdes"; - reg = <0x0 0x900000 0x0 0x2000>; - reg-names = "serdes"; - #phy-cells = <2>; - power-domains = <&k3_pds 153>; - clocks = <&k3_clks 153 4>, <&k3_clks 153 1>, - <&serdes1 AM654_SERDES_LO_REFCLK>; - clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", - "serdes0_ro_refclk"; - assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; - assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>; - ti,serdes-clk = <&serdes0_clk>; - mux-controls = <&serdes_mux 0>; - #clock-cells = <1>; -}; - -Example for PCIe consumer node using the SERDES PHY specifier is given below. -&pcie0_rc { - num-lanes = <2>; - phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>; - phy-names = "pcie-phy0", "pcie-phy1"; -}; diff --git a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml new file mode 100644 index 000000000000..62dcb84c08aa --- /dev/null +++ b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.yaml @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/ti,phy-am654-serdes.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI AM654 SERDES binding + +description: + This binding describes the TI AM654 SERDES. AM654 SERDES can be configured + to be used with either PCIe or USB or SGMII. + +maintainers: + - Kishon Vijay Abraham I + +properties: + compatible: + enum: + - ti,phy-am654-serdes + + reg: + maxItems: 1 + + reg-names: + items: + - const: serdes + + power-domains: + maxItems: 1 + + clocks: + maxItems: 3 + description: + Three input clocks referring to left input reference clock, refclk and right input reference + clock. + + assigned-clocks: + $ref: "/schemas/types.yaml#/definitions/phandle-array" + assigned-clock-parents: + $ref: "/schemas/types.yaml#/definitions/phandle-array" + + '#phy-cells': + const: 2 + description: + The 1st cell corresponds to the phy type (should be one of the types specified in + include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes lane function. + + ti,serdes-clk: + description: Phandle to the SYSCON entry required for configuring SERDES clock selection. + $ref: /schemas/types.yaml#/definitions/phandle + + '#clock-cells': + const: 1 + + mux-controls: + maxItems: 1 + description: Phandle to the SYSCON entry required for configuring SERDES lane function. + + clock-output-names: + oneOf: + - description: Clock output names for SERDES 0 + items: + - const: serdes0_cmu_refclk + - const: serdes0_lo_refclk + - const: serdes0_ro_refclk + - description: Clock output names for SERDES 1 + items: + - const: serdes1_cmu_refclk + - const: serdes1_lo_refclk + - const: serdes1_ro_refclk + +required: + - compatible + - reg + - power-domains + - clocks + - assigned-clocks + - assigned-clock-parents + - ti,serdes-clk + - mux-controls + - clock-output-names + +additionalProperties: false + +examples: + - | + #include + + serdes0: serdes@900000 { + compatible = "ti,phy-am654-serdes"; + reg = <0x900000 0x2000>; + reg-names = "serdes"; + #phy-cells = <2>; + power-domains = <&k3_pds 153>; + clocks = <&k3_clks 153 4>, <&k3_clks 153 1>, + <&serdes1 AM654_SERDES_LO_REFCLK>; + clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", "serdes0_ro_refclk"; + assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; + assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>; + ti,serdes-clk = <&serdes0_clk>; + mux-controls = <&serdes_mux 0>; + #clock-cells = <1>; + }; -- cgit v1.2.3 From 5711af410c28d2b9c99a91e8e6fe9ba6520771f0 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 27 Jul 2021 19:55:23 +0100 Subject: dt-bindings: phy: renesas,usb2-phy: Document RZ/G2L phy bindings Document USB phy bindings for RZ/G2L SoC. RZ/G2L USB2.0 phy uses line ctrl register for OTG_ID pin changes. It uses a different OTG-BC interrupt bit for device recognition. Apart from this, the PHY reset is controlled by USBPHY control IP and Document reset is a required property. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar Reviewed-by: Yoshihiro Shimoda Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210727185527.19907-3-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- .../devicetree/bindings/phy/renesas,usb2-phy.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml index d5dc5a3cdceb..3a6e1165419c 100644 --- a/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml +++ b/Documentation/devicetree/bindings/phy/renesas,usb2-phy.yaml @@ -30,6 +30,11 @@ properties: - renesas,usb2-phy-r8a77995 # R-Car D3 - const: renesas,rcar-gen3-usb2-phy + - items: + - enum: + - renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC} + - const: renesas,rzg2l-usb2-phy # RZ/G2L family + reg: maxItems: 1 @@ -91,6 +96,16 @@ required: - clocks - '#phy-cells' +allOf: + - if: + properties: + compatible: + contains: + const: renesas,rzg2l-usb2-phy + then: + required: + - resets + additionalProperties: false examples: -- cgit v1.2.3 From b0512a6ec0cd6dcea659d834592bbcb0cae127a4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 27 Jul 2021 19:55:24 +0100 Subject: phy: renesas: phy-rcar-gen3-usb2: Add USB2.0 PHY support for RZ/G2L This patch adds USB2.0 PHY support for RZ/G2L SoC. We need to use a different compatible string due to some differences with R-Car Gen3 USB2.0 PHY. It uses line ctrl register for OTG_ID pin changes and different OTG-BC interrupt bit for device recognition. Signed-off-by: Biju Das Reviewed-by: Lad Prabhakar Reviewed-by: Yoshihiro Shimoda Tested-by: Yoshihiro Shimoda # on R-Car Link: https://lore.kernel.org/r/20210727185527.19907-4-biju.das.jz@bp.renesas.com Signed-off-by: Vinod Koul --- drivers/phy/renesas/phy-rcar-gen3-usb2.c | 97 ++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 24 deletions(-) diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index fbc55232120e..9de617ca9daa 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c @@ -64,6 +64,7 @@ /* VBCTRL */ #define USB2_VBCTRL_OCCLREN BIT(16) #define USB2_VBCTRL_DRVVBUSSEL BIT(8) +#define USB2_VBCTRL_VBOUT BIT(0) /* LINECTRL1 */ #define USB2_LINECTRL1_DPRPD_EN BIT(19) @@ -78,6 +79,10 @@ #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_DRVVBUS BIT(4) +/* RZ/G2L specific */ +#define USB2_OBINT_IDCHG_EN BIT(0) +#define USB2_LINECTRL1_USB2_IDMON BIT(0) + #define NUM_OF_PHYS 4 enum rcar_gen3_phy_index { PHY_INDEX_BOTH_HC, @@ -112,9 +117,16 @@ struct rcar_gen3_chan { struct mutex lock; /* protects rphys[...].powered */ enum usb_dr_mode dr_mode; int irq; + u32 obint_enable_bits; bool extcon_host; bool is_otg_channel; bool uses_otg_pins; + bool soc_no_adp_ctrl; +}; + +struct rcar_gen3_phy_drv_data { + const struct phy_ops *phy_usb2_ops; + bool no_adp_ctrl; }; /* @@ -172,14 +184,22 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) { void __iomem *usb2_base = ch->base; - u32 val = readl(usb2_base + USB2_ADPCTRL); + u32 vbus_ctrl_reg = USB2_ADPCTRL; + u32 vbus_ctrl_val = USB2_ADPCTRL_DRVVBUS; + u32 val; dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); + if (ch->soc_no_adp_ctrl) { + vbus_ctrl_reg = USB2_VBCTRL; + vbus_ctrl_val = USB2_VBCTRL_VBOUT; + } + + val = readl(usb2_base + vbus_ctrl_reg); if (vbus) - val |= USB2_ADPCTRL_DRVVBUS; + val |= vbus_ctrl_val; else - val &= ~USB2_ADPCTRL_DRVVBUS; - writel(val, usb2_base + USB2_ADPCTRL); + val &= ~vbus_ctrl_val; + writel(val, usb2_base + vbus_ctrl_reg); } static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) @@ -188,9 +208,9 @@ static void rcar_gen3_control_otg_irq(struct rcar_gen3_chan *ch, int enable) u32 val = readl(usb2_base + USB2_OBINTEN); if (ch->uses_otg_pins && enable) - val |= USB2_OBINT_BITS; + val |= ch->obint_enable_bits; else - val &= ~USB2_OBINT_BITS; + val &= ~ch->obint_enable_bits; writel(val, usb2_base + USB2_OBINTEN); } @@ -252,6 +272,9 @@ static bool rcar_gen3_check_id(struct rcar_gen3_chan *ch) if (!ch->uses_otg_pins) return (ch->dr_mode == USB_DR_MODE_HOST) ? false : true; + if (ch->soc_no_adp_ctrl) + return !!(readl(ch->base + USB2_LINECTRL1) & USB2_LINECTRL1_USB2_IDMON); + return !!(readl(ch->base + USB2_ADPCTRL) & USB2_ADPCTRL_IDDIG); } @@ -376,16 +399,17 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) USB2_LINECTRL1_DMRPD_EN | USB2_LINECTRL1_DM_RPD; writel(val, usb2_base + USB2_LINECTRL1); - val = readl(usb2_base + USB2_VBCTRL); - val &= ~USB2_VBCTRL_OCCLREN; - writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); - val = readl(usb2_base + USB2_ADPCTRL); - writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); - + if (!ch->soc_no_adp_ctrl) { + val = readl(usb2_base + USB2_VBCTRL); + val &= ~USB2_VBCTRL_OCCLREN; + writel(val | USB2_VBCTRL_DRVVBUSSEL, usb2_base + USB2_VBCTRL); + val = readl(usb2_base + USB2_ADPCTRL); + writel(val | USB2_ADPCTRL_IDPULLUP, usb2_base + USB2_ADPCTRL); + } msleep(20); writel(0xffffffff, usb2_base + USB2_OBINTSTA); - writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTEN); + writel(ch->obint_enable_bits, usb2_base + USB2_OBINTEN); rcar_gen3_device_recognition(ch); } @@ -397,9 +421,9 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) u32 status = readl(usb2_base + USB2_OBINTSTA); irqreturn_t ret = IRQ_NONE; - if (status & USB2_OBINT_BITS) { + if (status & ch->obint_enable_bits) { dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); - writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); + writel(ch->obint_enable_bits, usb2_base + USB2_OBINTSTA); rcar_gen3_device_recognition(ch); ret = IRQ_HANDLED; } @@ -535,26 +559,45 @@ static const struct phy_ops rz_g1c_phy_usb2_ops = { .owner = THIS_MODULE, }; +static const struct rcar_gen3_phy_drv_data rcar_gen3_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .no_adp_ctrl = false, +}; + +static const struct rcar_gen3_phy_drv_data rz_g1c_phy_usb2_data = { + .phy_usb2_ops = &rz_g1c_phy_usb2_ops, + .no_adp_ctrl = false, +}; + +static const struct rcar_gen3_phy_drv_data rz_g2l_phy_usb2_data = { + .phy_usb2_ops = &rcar_gen3_phy_usb2_ops, + .no_adp_ctrl = true, +}; + static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { { .compatible = "renesas,usb2-phy-r8a77470", - .data = &rz_g1c_phy_usb2_ops, + .data = &rz_g1c_phy_usb2_data, }, { .compatible = "renesas,usb2-phy-r8a7795", - .data = &rcar_gen3_phy_usb2_ops, + .data = &rcar_gen3_phy_usb2_data, }, { .compatible = "renesas,usb2-phy-r8a7796", - .data = &rcar_gen3_phy_usb2_ops, + .data = &rcar_gen3_phy_usb2_data, }, { .compatible = "renesas,usb2-phy-r8a77965", - .data = &rcar_gen3_phy_usb2_ops, + .data = &rcar_gen3_phy_usb2_data, + }, + { + .compatible = "renesas,rzg2l-usb2-phy", + .data = &rz_g2l_phy_usb2_data, }, { .compatible = "renesas,rcar-gen3-usb2-phy", - .data = &rcar_gen3_phy_usb2_ops, + .data = &rcar_gen3_phy_usb2_data, }, { /* sentinel */ }, }; @@ -608,10 +651,10 @@ static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) { + const struct rcar_gen3_phy_drv_data *phy_data; struct device *dev = &pdev->dev; struct rcar_gen3_chan *channel; struct phy_provider *provider; - const struct phy_ops *phy_usb2_ops; int ret = 0, i; if (!dev->of_node) { @@ -627,6 +670,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) if (IS_ERR(channel->base)) return PTR_ERR(channel->base); + channel->obint_enable_bits = USB2_OBINT_BITS; /* get irq number here and request_irq for OTG in phy_init */ channel->irq = platform_get_irq_optional(pdev, 0); channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); @@ -653,16 +697,21 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) * And then, phy-core will manage runtime pm for this device. */ pm_runtime_enable(dev); - phy_usb2_ops = of_device_get_match_data(dev); - if (!phy_usb2_ops) { + + phy_data = of_device_get_match_data(dev); + if (!phy_data) { ret = -EINVAL; goto error; } + channel->soc_no_adp_ctrl = phy_data->no_adp_ctrl; + if (phy_data->no_adp_ctrl) + channel->obint_enable_bits = USB2_OBINT_IDCHG_EN; + mutex_init(&channel->lock); for (i = 0; i < NUM_OF_PHYS; i++) { channel->rphys[i].phy = devm_phy_create(dev, NULL, - phy_usb2_ops); + phy_data->phy_usb2_ops); if (IS_ERR(channel->rphys[i].phy)) { dev_err(dev, "Failed to create USB2 PHY\n"); ret = PTR_ERR(channel->rphys[i].phy); -- cgit v1.2.3 From 2433ab638f10b6ca94416df501bc8cb24589c6a8 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 4 Aug 2021 17:05:05 +0300 Subject: dt-bindings: phy: qcom,qmp: Add IPQ6018 USB3 PHY Add compatible string for USB3 PHY in Qualcomm IPQ6018 SoC. Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/3d86f45004fe2fcbae0a2cd197df81a1fd076a1e.1628085910.git.baruch@tkos.co.il Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml index 242560ff52a4..47d99001d2dd 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: - qcom,ipq6018-qmp-pcie-phy + - qcom,ipq6018-qmp-usb3-phy - qcom,ipq8074-qmp-pcie-phy - qcom,ipq8074-qmp-usb3-phy - qcom,msm8996-qmp-pcie-phy -- cgit v1.2.3 From 23fd679249df82b57390c8f4f0f290fd1f7b3505 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Wed, 4 Aug 2021 17:05:06 +0300 Subject: phy: qcom-qmp: add USB3 PHY support for IPQ6018 Initialization is identical to the IPQ8074 USB3 PHY. Signed-off-by: Baruch Siach Link: https://lore.kernel.org/r/6eec7ef4ecd1e8360ebe8e425151121684e997ed.1628085910.git.baruch@tkos.co.il Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 5e302830d061..dd6174084600 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -5402,6 +5402,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,ipq6018-qmp-pcie-phy", .data = &ipq6018_pciephy_cfg, + }, { + .compatible = "qcom,ipq6018-qmp-usb3-phy", + .data = &ipq8074_usb3phy_cfg, }, { .compatible = "qcom,sc7180-qmp-usb3-phy", .data = &sc7180_usb3phy_cfg, -- cgit v1.2.3 From 2a8faf8dfd7da3c8234f36bc72fd027a5a64db8a Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 6 Aug 2021 12:32:36 +0200 Subject: firmware: xilinx: Fix incorrect names in kernel-doc There are some c&p issues reported by kernel-doc as: drivers/firmware/xilinx/zynqmp.c:676: warning: expecting prototype for zynqmp_pm_write_ggs(). Prototype was for zynqmp_pm_read_ggs() instead drivers/firmware/xilinx/zynqmp.c:710: warning: expecting prototype for zynqmp_pm_write_pggs(). Prototype was for zynqmp_pm_read_pggs() instead drivers/firmware/xilinx/zynqmp.c:1023: warning: expecting prototype for zynqmp_pm_aes(). Prototype was for zynqmp_pm_aes_engine() instead Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/a81edd4fc6cff4bd7e4984fceda941b9e9ab01bf.1628245954.git.michal.simek@xilinx.com Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/xilinx/zynqmp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 2db571da9ad8..a3cadbaf3cba 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -664,7 +664,7 @@ int zynqmp_pm_write_ggs(u32 index, u32 value) EXPORT_SYMBOL_GPL(zynqmp_pm_write_ggs); /** - * zynqmp_pm_write_ggs() - PM API for reading global general storage (ggs) + * zynqmp_pm_read_ggs() - PM API for reading global general storage (ggs) * @index: GGS register index * @value: Register value to be written * @@ -697,7 +697,7 @@ int zynqmp_pm_write_pggs(u32 index, u32 value) EXPORT_SYMBOL_GPL(zynqmp_pm_write_pggs); /** - * zynqmp_pm_write_pggs() - PM API for reading persistent global general + * zynqmp_pm_read_pggs() - PM API for reading persistent global general * storage (pggs) * @index: PGGS register index * @value: Register value to be written @@ -1029,7 +1029,7 @@ int zynqmp_pm_load_pdi(const u32 src, const u64 address) EXPORT_SYMBOL_GPL(zynqmp_pm_load_pdi); /** - * zynqmp_pm_aes - Access AES hardware to encrypt/decrypt the data using + * zynqmp_pm_aes_engine - Access AES hardware to encrypt/decrypt the data using * AES-GCM core. * @address: Address of the AesParams structure. * @out: Returned output value -- cgit v1.2.3 From cca5644c05220df7e9f9d973fa57060cf4b0ddb5 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 6 Aug 2021 09:59:44 +0100 Subject: dt-bindings: nvmem: qfprom: Add optional power-domains property qfprom devices on some SoCs need to vote on the performance state of a power-domain, so add the power-domains optional property to the bindings Reviewed-by: Douglas Anderson Acked-by: Rob Herring Signed-off-by: Rajendra Nayak Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210806085947.22682-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml index 861b205016b1..dede8892ee01 100644 --- a/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml +++ b/Documentation/devicetree/bindings/nvmem/qcom,qfprom.yaml @@ -51,6 +51,9 @@ properties: vcc-supply: description: Our power supply. + power-domains: + maxItems: 1 + # Needed if any child nodes are present. "#address-cells": const: 1 -- cgit v1.2.3 From 11c4b3e264d68ba6dcd52d12dbcfd3f564f2f137 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 6 Aug 2021 09:59:45 +0100 Subject: nvmem: qfprom: Fix up qfprom_disable_fuse_blowing() ordering qfprom_disable_fuse_blowing() disables a bunch of resources, and then does a few register writes in the 'conf' address space. It works perhaps because the resources are needed only for the 'raw' register space writes, and that the 'conf' space allows read/writes regardless. However that makes the code look confusing, so just move the register writes before turning off the resources in the function. Reviewed-by: Douglas Anderson Signed-off-by: Rajendra Nayak Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210806085947.22682-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index 81fbad5e939d..b0ca4c626466 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -139,6 +139,9 @@ static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, { int ret; + writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); + writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET); + /* * This may be a shared rail and may be able to run at a lower rate * when we're not blowing fuses. At the moment, the regulator framework @@ -159,9 +162,6 @@ static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, "Failed to set clock rate for disable (ignoring)\n"); clk_disable_unprepare(priv->secclk); - - writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); - writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET); } /** -- cgit v1.2.3 From 7b808449f572d07bee840cd9da7e2fe6a1b8f4b5 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Fri, 6 Aug 2021 09:59:46 +0100 Subject: nvmem: qfprom: sc7280: Handle the additional power-domains vote On sc7280, to reliably blow fuses, we need an additional vote on max performance state of 'MX' power-domain. Add support for power-domain performance state voting in the driver. Reviewed-by: Douglas Anderson Signed-off-by: Rajendra Nayak Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210806085947.22682-4-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/qfprom.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index b0ca4c626466..c500d6235bf6 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -142,6 +144,9 @@ static void qfprom_disable_fuse_blowing(const struct qfprom_priv *priv, writel(old->timer_val, priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); writel(old->accel_val, priv->qfpconf + QFPROM_ACCEL_OFFSET); + dev_pm_genpd_set_performance_state(priv->dev, 0); + pm_runtime_put(priv->dev); + /* * This may be a shared rail and may be able to run at a lower rate * when we're not blowing fuses. At the moment, the regulator framework @@ -212,6 +217,14 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, goto err_clk_rate_set; } + ret = pm_runtime_get_sync(priv->dev); + if (ret < 0) { + pm_runtime_put_noidle(priv->dev); + dev_err(priv->dev, "Failed to enable power-domain\n"); + goto err_reg_enable; + } + dev_pm_genpd_set_performance_state(priv->dev, INT_MAX); + old->timer_val = readl(priv->qfpconf + QFPROM_BLOW_TIMER_OFFSET); old->accel_val = readl(priv->qfpconf + QFPROM_ACCEL_OFFSET); writel(priv->soc_data->qfprom_blow_timer_value, @@ -221,6 +234,8 @@ static int qfprom_enable_fuse_blowing(const struct qfprom_priv *priv, return 0; +err_reg_enable: + regulator_disable(priv->vcc); err_clk_rate_set: clk_set_rate(priv->secclk, old->clk_rate); err_clk_prepared: @@ -320,6 +335,11 @@ static int qfprom_reg_read(void *context, return 0; } +static void qfprom_runtime_disable(void *data) +{ + pm_runtime_disable(data); +} + static const struct qfprom_soc_data qfprom_7_8_data = { .accel_value = 0xD10, .qfprom_blow_timer_value = 25, @@ -420,6 +440,11 @@ static int qfprom_probe(struct platform_device *pdev) econfig.reg_write = qfprom_reg_write; } + pm_runtime_enable(dev); + ret = devm_add_action_or_reset(dev, qfprom_runtime_disable, dev); + if (ret) + return ret; + nvmem = devm_nvmem_register(dev, &econfig); return PTR_ERR_OR_ZERO(nvmem); -- cgit v1.2.3 From de0534df93474f268486c486ea7e01b44a478026 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 6 Aug 2021 09:59:47 +0100 Subject: nvmem: core: fix error handling while validating keepout regions Current error path on failure of validating keepout regions is calling put_device, eventhough the device is not even registered at that point. Fix this by adding proper error handling of freeing ida and nvmem. Fixes: fd3bb8f54a88 ("nvmem: core: Add support for keepout regions") Cc: Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210806085947.22682-5-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index b3bc30a04ed7..3d87fadaa160 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -824,8 +824,11 @@ struct nvmem_device *nvmem_register(const struct nvmem_config *config) if (nvmem->nkeepout) { rval = nvmem_validate_keepouts(nvmem); - if (rval) - goto err_put_device; + if (rval) { + ida_free(&nvmem_ida, nvmem->id); + kfree(nvmem); + return ERR_PTR(rval); + } } dev_dbg(&nvmem->dev, "Registering nvmem device %s\n", config->name); -- cgit v1.2.3 From d81274f8fd8616724a86be0b9bab92f0f52651ef Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 23 Jul 2021 12:42:42 -0700 Subject: dt-bindings: interconnect: Add Qualcomm SC8180x DT bindings Add compatibles and port definitions for the SC8180x RPMH interconnect providers. Signed-off-by: Georgi Djakov [bjorn: Split defines from driver patch and added binding update] Signed-off-by: Bjorn Andersson Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20210723194243.3675795-1-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- .../bindings/interconnect/qcom,rpmh.yaml | 11 ++ include/dt-bindings/interconnect/qcom,sc8180x.h | 185 +++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 include/dt-bindings/interconnect/qcom,sc8180x.h diff --git a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml index 5accc0d113be..3fd1a134162d 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,rpmh.yaml @@ -49,6 +49,17 @@ properties: - qcom,sc7280-mmss-noc - qcom,sc7280-nsp-noc - qcom,sc7280-system-noc + - qcom,sc8180x-aggre1-noc + - qcom,sc8180x-aggre2-noc + - qcom,sc8180x-camnoc-virt + - qcom,sc8180x-compute-noc + - qcom,sc8180x-config-noc + - qcom,sc8180x-dc-noc + - qcom,sc8180x-gem-noc + - qcom,sc8180x-ipa-virt + - qcom,sc8180x-mc-virt + - qcom,sc8180x-mmss-noc + - qcom,sc8180x-system-noc - qcom,sdm845-aggre1-noc - qcom,sdm845-aggre2-noc - qcom,sdm845-config-noc diff --git a/include/dt-bindings/interconnect/qcom,sc8180x.h b/include/dt-bindings/interconnect/qcom,sc8180x.h new file mode 100644 index 000000000000..235b525d2803 --- /dev/null +++ b/include/dt-bindings/interconnect/qcom,sc8180x.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Qualcomm SC8180x interconnect IDs + * + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ + +#ifndef __DT_BINDINGS_INTERCONNECT_QCOM_SC8180X_H +#define __DT_BINDINGS_INTERCONNECT_QCOM_SC8180X_H + +#define MASTER_A1NOC_CFG 0 +#define MASTER_UFS_CARD 1 +#define MASTER_UFS_GEN4 2 +#define MASTER_UFS_MEM 3 +#define MASTER_USB3 4 +#define MASTER_USB3_1 5 +#define MASTER_USB3_2 6 +#define A1NOC_SNOC_SLV 7 +#define SLAVE_SERVICE_A1NOC 8 + +#define MASTER_A2NOC_CFG 0 +#define MASTER_QDSS_BAM 1 +#define MASTER_QSPI_0 2 +#define MASTER_QSPI_1 3 +#define MASTER_QUP_0 4 +#define MASTER_QUP_1 5 +#define MASTER_QUP_2 6 +#define MASTER_SENSORS_AHB 7 +#define MASTER_CRYPTO_CORE_0 8 +#define MASTER_IPA 9 +#define MASTER_EMAC 10 +#define MASTER_PCIE 11 +#define MASTER_PCIE_1 12 +#define MASTER_PCIE_2 13 +#define MASTER_PCIE_3 14 +#define MASTER_QDSS_ETR 15 +#define MASTER_SDCC_2 16 +#define MASTER_SDCC_4 17 +#define A2NOC_SNOC_SLV 18 +#define SLAVE_ANOC_PCIE_GEM_NOC 19 +#define SLAVE_SERVICE_A2NOC 20 + +#define MASTER_CAMNOC_HF0_UNCOMP 0 +#define MASTER_CAMNOC_HF1_UNCOMP 1 +#define MASTER_CAMNOC_SF_UNCOMP 2 +#define SLAVE_CAMNOC_UNCOMP 3 + +#define MASTER_NPU 0 +#define SLAVE_CDSP_MEM_NOC 1 + +#define SNOC_CNOC_MAS 0 +#define SLAVE_A1NOC_CFG 1 +#define SLAVE_A2NOC_CFG 2 +#define SLAVE_AHB2PHY_CENTER 3 +#define SLAVE_AHB2PHY_EAST 4 +#define SLAVE_AHB2PHY_WEST 5 +#define SLAVE_AHB2PHY_SOUTH 6 +#define SLAVE_AOP 7 +#define SLAVE_AOSS 8 +#define SLAVE_CAMERA_CFG 9 +#define SLAVE_CLK_CTL 10 +#define SLAVE_CDSP_CFG 11 +#define SLAVE_RBCPR_CX_CFG 12 +#define SLAVE_RBCPR_MMCX_CFG 13 +#define SLAVE_RBCPR_MX_CFG 14 +#define SLAVE_CRYPTO_0_CFG 15 +#define SLAVE_CNOC_DDRSS 16 +#define SLAVE_DISPLAY_CFG 17 +#define SLAVE_EMAC_CFG 18 +#define SLAVE_GLM 19 +#define SLAVE_GRAPHICS_3D_CFG 20 +#define SLAVE_IMEM_CFG 21 +#define SLAVE_IPA_CFG 22 +#define SLAVE_CNOC_MNOC_CFG 23 +#define SLAVE_NPU_CFG 24 +#define SLAVE_PCIE_0_CFG 25 +#define SLAVE_PCIE_1_CFG 26 +#define SLAVE_PCIE_2_CFG 27 +#define SLAVE_PCIE_3_CFG 28 +#define SLAVE_PDM 29 +#define SLAVE_PIMEM_CFG 30 +#define SLAVE_PRNG 31 +#define SLAVE_QDSS_CFG 32 +#define SLAVE_QSPI_0 33 +#define SLAVE_QSPI_1 34 +#define SLAVE_QUP_1 35 +#define SLAVE_QUP_2 36 +#define SLAVE_QUP_0 37 +#define SLAVE_SDCC_2 38 +#define SLAVE_SDCC_4 39 +#define SLAVE_SECURITY 40 +#define SLAVE_SNOC_CFG 41 +#define SLAVE_SPSS_CFG 42 +#define SLAVE_TCSR 43 +#define SLAVE_TLMM_EAST 44 +#define SLAVE_TLMM_SOUTH 45 +#define SLAVE_TLMM_WEST 46 +#define SLAVE_TSIF 47 +#define SLAVE_UFS_CARD_CFG 48 +#define SLAVE_UFS_MEM_0_CFG 49 +#define SLAVE_UFS_MEM_1_CFG 50 +#define SLAVE_USB3 51 +#define SLAVE_USB3_1 52 +#define SLAVE_USB3_2 53 +#define SLAVE_VENUS_CFG 54 +#define SLAVE_VSENSE_CTRL_CFG 55 +#define SLAVE_SERVICE_CNOC 56 + +#define MASTER_CNOC_DC_NOC 0 +#define SLAVE_GEM_NOC_CFG 1 +#define SLAVE_LLCC_CFG 2 + +#define MASTER_AMPSS_M0 0 +#define MASTER_GPU_TCU 1 +#define MASTER_SYS_TCU 2 +#define MASTER_GEM_NOC_CFG 3 +#define MASTER_COMPUTE_NOC 4 +#define MASTER_GRAPHICS_3D 5 +#define MASTER_MNOC_HF_MEM_NOC 6 +#define MASTER_MNOC_SF_MEM_NOC 7 +#define MASTER_GEM_NOC_PCIE_SNOC 8 +#define MASTER_SNOC_GC_MEM_NOC 9 +#define MASTER_SNOC_SF_MEM_NOC 10 +#define MASTER_ECC 11 +#define SLAVE_MSS_PROC_MS_MPU_CFG 12 +#define SLAVE_ECC 13 +#define SLAVE_GEM_NOC_SNOC 14 +#define SLAVE_LLCC 15 +#define SLAVE_SERVICE_GEM_NOC 16 +#define SLAVE_SERVICE_GEM_NOC_1 17 + +#define MASTER_IPA_CORE 0 +#define SLAVE_IPA_CORE 1 + +#define MASTER_LLCC 0 +#define SLAVE_EBI_CH0 1 + +#define MASTER_CNOC_MNOC_CFG 0 +#define MASTER_CAMNOC_HF0 1 +#define MASTER_CAMNOC_HF1 2 +#define MASTER_CAMNOC_SF 3 +#define MASTER_MDP_PORT0 4 +#define MASTER_MDP_PORT1 5 +#define MASTER_ROTATOR 6 +#define MASTER_VIDEO_P0 7 +#define MASTER_VIDEO_P1 8 +#define MASTER_VIDEO_PROC 9 +#define SLAVE_MNOC_SF_MEM_NOC 10 +#define SLAVE_MNOC_HF_MEM_NOC 11 +#define SLAVE_SERVICE_MNOC 12 + +#define MASTER_SNOC_CFG 0 +#define A1NOC_SNOC_MAS 1 +#define A2NOC_SNOC_MAS 2 +#define MASTER_GEM_NOC_SNOC 3 +#define MASTER_PIMEM 4 +#define MASTER_GIC 5 +#define SLAVE_APPSS 6 +#define SNOC_CNOC_SLV 7 +#define SLAVE_SNOC_GEM_NOC_GC 8 +#define SLAVE_SNOC_GEM_NOC_SF 9 +#define SLAVE_OCIMEM 10 +#define SLAVE_PIMEM 11 +#define SLAVE_SERVICE_SNOC 12 +#define SLAVE_PCIE_0 13 +#define SLAVE_PCIE_1 14 +#define SLAVE_PCIE_2 15 +#define SLAVE_PCIE_3 16 +#define SLAVE_QDSS_STM 17 +#define SLAVE_TCU 18 + +#define MASTER_MNOC_HF_MEM_NOC_DISPLAY 0 +#define MASTER_MNOC_SF_MEM_NOC_DISPLAY 1 +#define SLAVE_LLCC_DISPLAY 2 + +#define MASTER_LLCC_DISPLAY 0 +#define SLAVE_EBI_CH0_DISPLAY 1 + +#define MASTER_MDP_PORT0_DISPLAY 0 +#define MASTER_MDP_PORT1_DISPLAY 1 +#define MASTER_ROTATOR_DISPLAY 2 +#define SLAVE_MNOC_SF_MEM_NOC_DISPLAY 3 +#define SLAVE_MNOC_HF_MEM_NOC_DISPLAY 4 + +#endif -- cgit v1.2.3 From 9c8c6bac1ae86f6902baa938101902fb3a0a100b Mon Sep 17 00:00:00 2001 From: Georgi Djakov Date: Fri, 23 Jul 2021 12:42:43 -0700 Subject: interconnect: qcom: Add SC8180x providers The SC8180x contains the usual RPMH based interconnect providers, add a driver which defines the various busses and ports. Signed-off-by: Georgi Djakov Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210723194243.3675795-2-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/Kconfig | 9 + drivers/interconnect/qcom/Makefile | 2 + drivers/interconnect/qcom/sc8180x.c | 626 ++++++++++++++++++++++++++++++++++++ drivers/interconnect/qcom/sc8180x.h | 172 ++++++++++ 4 files changed, 809 insertions(+) create mode 100644 drivers/interconnect/qcom/sc8180x.c create mode 100644 drivers/interconnect/qcom/sc8180x.h diff --git a/drivers/interconnect/qcom/Kconfig b/drivers/interconnect/qcom/Kconfig index 0d7a2500d0b8..daf1e25f6042 100644 --- a/drivers/interconnect/qcom/Kconfig +++ b/drivers/interconnect/qcom/Kconfig @@ -83,6 +83,15 @@ config INTERCONNECT_QCOM_SC7280 This is a driver for the Qualcomm Network-on-Chip on sc7280-based platforms. +config INTERCONNECT_QCOM_SC8180X + tristate "Qualcomm SC8180X interconnect driver" + depends on INTERCONNECT_QCOM_RPMH_POSSIBLE + select INTERCONNECT_QCOM_RPMH + select INTERCONNECT_QCOM_BCM_VOTER + help + This is a driver for the Qualcomm Network-on-Chip on sc8180x-based + platforms. + config INTERCONNECT_QCOM_SDM660 tristate "Qualcomm SDM660 interconnect driver" depends on INTERCONNECT_QCOM diff --git a/drivers/interconnect/qcom/Makefile b/drivers/interconnect/qcom/Makefile index 2880129a6fe4..69300b1d48ef 100644 --- a/drivers/interconnect/qcom/Makefile +++ b/drivers/interconnect/qcom/Makefile @@ -9,6 +9,7 @@ qnoc-qcs404-objs := qcs404.o icc-rpmh-obj := icc-rpmh.o qnoc-sc7180-objs := sc7180.o qnoc-sc7280-objs := sc7280.o +qnoc-sc8180x-objs := sc8180x.o qnoc-sdm660-objs := sdm660.o qnoc-sdm845-objs := sdm845.o qnoc-sdx55-objs := sdx55.o @@ -26,6 +27,7 @@ obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o +obj-$(CONFIG_INTERCONNECT_QCOM_SC8180X) += qnoc-sc8180x.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o diff --git a/drivers/interconnect/qcom/sc8180x.c b/drivers/interconnect/qcom/sc8180x.c new file mode 100644 index 000000000000..e9adf05b9330 --- /dev/null +++ b/drivers/interconnect/qcom/sc8180x.c @@ -0,0 +1,626 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Linaro Ltd. + */ + +#include +#include +#include +#include + +#include + +#include "bcm-voter.h" +#include "icc-rpmh.h" +#include "sc8180x.h" + +DEFINE_QNODE(mas_qhm_a1noc_cfg, SC8180X_MASTER_A1NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A1NOC); +DEFINE_QNODE(mas_xm_ufs_card, SC8180X_MASTER_UFS_CARD, 1, 8, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_ufs_g4, SC8180X_MASTER_UFS_GEN4, 1, 8, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_ufs_mem, SC8180X_MASTER_UFS_MEM, 1, 8, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_usb3_0, SC8180X_MASTER_USB3, 1, 8, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_usb3_1, SC8180X_MASTER_USB3_1, 1, 8, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_usb3_2, SC8180X_MASTER_USB3_2, 1, 16, SC8180X_A1NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_a2noc_cfg, SC8180X_MASTER_A2NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_A2NOC); +DEFINE_QNODE(mas_qhm_qdss_bam, SC8180X_MASTER_QDSS_BAM, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_qspi, SC8180X_MASTER_QSPI_0, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_qspi1, SC8180X_MASTER_QSPI_1, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_qup0, SC8180X_MASTER_QUP_0, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_qup1, SC8180X_MASTER_QUP_1, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_qup2, SC8180X_MASTER_QUP_2, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qhm_sensorss_ahb, SC8180X_MASTER_SENSORS_AHB, 1, 4, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qxm_crypto, SC8180X_MASTER_CRYPTO_CORE_0, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qxm_ipa, SC8180X_MASTER_IPA, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_emac, SC8180X_MASTER_EMAC, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_pcie3_0, SC8180X_MASTER_PCIE, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(mas_xm_pcie3_1, SC8180X_MASTER_PCIE_1, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(mas_xm_pcie3_2, SC8180X_MASTER_PCIE_2, 1, 8, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(mas_xm_pcie3_3, SC8180X_MASTER_PCIE_3, 1, 16, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC); +DEFINE_QNODE(mas_xm_qdss_etr, SC8180X_MASTER_QDSS_ETR, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_sdc2, SC8180X_MASTER_SDCC_2, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_xm_sdc4, SC8180X_MASTER_SDCC_4, 1, 8, SC8180X_A2NOC_SNOC_SLV); +DEFINE_QNODE(mas_qxm_camnoc_hf0_uncomp, SC8180X_MASTER_CAMNOC_HF0_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP); +DEFINE_QNODE(mas_qxm_camnoc_hf1_uncomp, SC8180X_MASTER_CAMNOC_HF1_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP); +DEFINE_QNODE(mas_qxm_camnoc_sf_uncomp, SC8180X_MASTER_CAMNOC_SF_UNCOMP, 1, 32, SC8180X_SLAVE_CAMNOC_UNCOMP); +DEFINE_QNODE(mas_qnm_npu, SC8180X_MASTER_NPU, 1, 32, SC8180X_SLAVE_CDSP_MEM_NOC); +DEFINE_QNODE(mas_qnm_snoc, SC8180X_SNOC_CNOC_MAS, 1, 8, SC8180X_SLAVE_TLMM_SOUTH, SC8180X_SLAVE_CDSP_CFG, SC8180X_SLAVE_SPSS_CFG, SC8180X_SLAVE_CAMERA_CFG, SC8180X_SLAVE_SDCC_4, SC8180X_SLAVE_AHB2PHY_CENTER, SC8180X_SLAVE_SDCC_2, SC8180X_SLAVE_PCIE_2_CFG, SC8180X_SLAVE_CNOC_MNOC_CFG, SC8180X_SLAVE_EMAC_CFG, SC8180X_SLAVE_QSPI_0, SC8180X_SLAVE_QSPI_1, SC8180X_SLAVE_TLMM_EAST, SC8180X_SLAVE_SNOC_CFG, SC8180X_SLAVE_AHB2PHY_EAST, SC8180X_SLAVE_GLM, SC8180X_SLAVE_PDM, SC8180X_SLAVE_PCIE_1_CFG, SC8180X_SLAVE_A2NOC_CFG, SC8180X_SLAVE_QDSS_CFG, SC8180X_SLAVE_DISPLAY_CFG, SC8180X_SLAVE_TCSR, SC8180X_SLAVE_UFS_MEM_0_CFG, SC8180X_SLAVE_CNOC_DDRSS, SC8180X_SLAVE_PCIE_0_CFG, SC8180X_SLAVE_QUP_1, SC8180X_SLAVE_QUP_2, SC8180X_SLAVE_NPU_CFG, SC8180X_SLAVE_CRYPTO_0_CFG, SC8180X_SLAVE_GRAPHICS_3D_CFG, SC8180X_SLAVE_VENUS_CFG, SC8180X_SLAVE_TSIF, SC8180X_SLAVE_IPA_CFG, SC8180X_SLAVE_CLK_CTL, SC8180X_SLAVE_SECURITY, SC8180X_SLAVE_AOP, SC8180X_SLAVE_AHB2PHY_WEST, SC8180X_SLAVE_AHB2PHY_SOUTH, SC8180X_SLAVE_SERVICE_CNOC, SC8180X_SLAVE_UFS_CARD_CFG, SC8180X_SLAVE_USB3_1, SC8180X_SLAVE_USB3_2, SC8180X_SLAVE_PCIE_3_CFG, SC8180X_SLAVE_RBCPR_CX_CFG, SC8180X_SLAVE_TLMM_WEST, SC8180X_SLAVE_A1NOC_CFG, SC8180X_SLAVE_AOSS, SC8180X_SLAVE_PRNG, SC8180X_SLAVE_VSENSE_CTRL_CFG, SC8180X_SLAVE_QUP_0, SC8180X_SLAVE_USB3, SC8180X_SLAVE_RBCPR_MMCX_CFG, SC8180X_SLAVE_PIMEM_CFG, SC8180X_SLAVE_UFS_MEM_1_CFG, SC8180X_SLAVE_RBCPR_MX_CFG, SC8180X_SLAVE_IMEM_CFG); +DEFINE_QNODE(mas_qhm_cnoc_dc_noc, SC8180X_MASTER_CNOC_DC_NOC, 1, 4, SC8180X_SLAVE_LLCC_CFG, SC8180X_SLAVE_GEM_NOC_CFG); +DEFINE_QNODE(mas_acm_apps, SC8180X_MASTER_AMPSS_M0, 4, 64, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_acm_gpu_tcu, SC8180X_MASTER_GPU_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_acm_sys_tcu, SC8180X_MASTER_SYS_TCU, 1, 8, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_qhm_gemnoc_cfg, SC8180X_MASTER_GEM_NOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_GEM_NOC_1, SC8180X_SLAVE_SERVICE_GEM_NOC, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG); +DEFINE_QNODE(mas_qnm_cmpnoc, SC8180X_MASTER_COMPUTE_NOC, 2, 32, SC8180X_SLAVE_ECC, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_qnm_gpu, SC8180X_MASTER_GRAPHICS_3D, 4, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_qnm_mnoc_hf, SC8180X_MASTER_MNOC_HF_MEM_NOC, 2, 32, SC8180X_SLAVE_LLCC); +DEFINE_QNODE(mas_qnm_mnoc_sf, SC8180X_MASTER_MNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_qnm_pcie, SC8180X_MASTER_GEM_NOC_PCIE_SNOC, 1, 32, SC8180X_SLAVE_LLCC, SC8180X_SLAVE_GEM_NOC_SNOC); +DEFINE_QNODE(mas_qnm_snoc_gc, SC8180X_MASTER_SNOC_GC_MEM_NOC, 1, 8, SC8180X_SLAVE_LLCC); +DEFINE_QNODE(mas_qnm_snoc_sf, SC8180X_MASTER_SNOC_SF_MEM_NOC, 1, 32, SC8180X_SLAVE_LLCC); +DEFINE_QNODE(mas_qxm_ecc, SC8180X_MASTER_ECC, 2, 32, SC8180X_SLAVE_LLCC); +DEFINE_QNODE(mas_ipa_core_master, SC8180X_MASTER_IPA_CORE, 1, 8, SC8180X_SLAVE_IPA_CORE); +DEFINE_QNODE(mas_llcc_mc, SC8180X_MASTER_LLCC, 8, 4, SC8180X_SLAVE_EBI_CH0); +DEFINE_QNODE(mas_qhm_mnoc_cfg, SC8180X_MASTER_CNOC_MNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_MNOC); +DEFINE_QNODE(mas_qxm_camnoc_hf0, SC8180X_MASTER_CAMNOC_HF0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(mas_qxm_camnoc_hf1, SC8180X_MASTER_CAMNOC_HF1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(mas_qxm_camnoc_sf, SC8180X_MASTER_CAMNOC_SF, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(mas_qxm_mdp0, SC8180X_MASTER_MDP_PORT0, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(mas_qxm_mdp1, SC8180X_MASTER_MDP_PORT1, 1, 32, SC8180X_SLAVE_MNOC_HF_MEM_NOC); +DEFINE_QNODE(mas_qxm_rot, SC8180X_MASTER_ROTATOR, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(mas_qxm_venus0, SC8180X_MASTER_VIDEO_P0, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(mas_qxm_venus1, SC8180X_MASTER_VIDEO_P1, 1, 32, SC8180X_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(mas_qxm_venus_arm9, SC8180X_MASTER_VIDEO_PROC, 1, 8, SC8180X_SLAVE_MNOC_SF_MEM_NOC); +DEFINE_QNODE(mas_qhm_snoc_cfg, SC8180X_MASTER_SNOC_CFG, 1, 4, SC8180X_SLAVE_SERVICE_SNOC); +DEFINE_QNODE(mas_qnm_aggre1_noc, SC8180X_A1NOC_SNOC_MAS, 1, 32, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_QDSS_STM); +DEFINE_QNODE(mas_qnm_aggre2_noc, SC8180X_A2NOC_SNOC_MAS, 1, 16, SC8180X_SLAVE_SNOC_GEM_NOC_SF, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_PCIE_3, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SLAVE_PCIE_2, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_PCIE_0, SC8180X_SLAVE_PCIE_1, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM); +DEFINE_QNODE(mas_qnm_gemnoc, SC8180X_MASTER_GEM_NOC_SNOC, 1, 8, SC8180X_SLAVE_PIMEM, SC8180X_SLAVE_OCIMEM, SC8180X_SLAVE_APPSS, SC8180X_SNOC_CNOC_SLV, SC8180X_SLAVE_TCU, SC8180X_SLAVE_QDSS_STM); +DEFINE_QNODE(mas_qxm_pimem, SC8180X_MASTER_PIMEM, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM); +DEFINE_QNODE(mas_xm_gic, SC8180X_MASTER_GIC, 1, 8, SC8180X_SLAVE_SNOC_GEM_NOC_GC, SC8180X_SLAVE_OCIMEM); +DEFINE_QNODE(slv_qns_a1noc_snoc, SC8180X_A1NOC_SNOC_SLV, 1, 32, SC8180X_A1NOC_SNOC_MAS); +DEFINE_QNODE(slv_srvc_aggre1_noc, SC8180X_SLAVE_SERVICE_A1NOC, 1, 4); +DEFINE_QNODE(slv_qns_a2noc_snoc, SC8180X_A2NOC_SNOC_SLV, 1, 16, SC8180X_A2NOC_SNOC_MAS); +DEFINE_QNODE(slv_qns_pcie_mem_noc, SC8180X_SLAVE_ANOC_PCIE_GEM_NOC, 1, 32, SC8180X_MASTER_GEM_NOC_PCIE_SNOC); +DEFINE_QNODE(slv_srvc_aggre2_noc, SC8180X_SLAVE_SERVICE_A2NOC, 1, 4); +DEFINE_QNODE(slv_qns_camnoc_uncomp, SC8180X_SLAVE_CAMNOC_UNCOMP, 1, 32); +DEFINE_QNODE(slv_qns_cdsp_mem_noc, SC8180X_SLAVE_CDSP_MEM_NOC, 2, 32, SC8180X_MASTER_COMPUTE_NOC); +DEFINE_QNODE(slv_qhs_a1_noc_cfg, SC8180X_SLAVE_A1NOC_CFG, 1, 4, SC8180X_MASTER_A1NOC_CFG); +DEFINE_QNODE(slv_qhs_a2_noc_cfg, SC8180X_SLAVE_A2NOC_CFG, 1, 4, SC8180X_MASTER_A2NOC_CFG); +DEFINE_QNODE(slv_qhs_ahb2phy_refgen_center, SC8180X_SLAVE_AHB2PHY_CENTER, 1, 4); +DEFINE_QNODE(slv_qhs_ahb2phy_refgen_east, SC8180X_SLAVE_AHB2PHY_EAST, 1, 4); +DEFINE_QNODE(slv_qhs_ahb2phy_refgen_west, SC8180X_SLAVE_AHB2PHY_WEST, 1, 4); +DEFINE_QNODE(slv_qhs_ahb2phy_south, SC8180X_SLAVE_AHB2PHY_SOUTH, 1, 4); +DEFINE_QNODE(slv_qhs_aop, SC8180X_SLAVE_AOP, 1, 4); +DEFINE_QNODE(slv_qhs_aoss, SC8180X_SLAVE_AOSS, 1, 4); +DEFINE_QNODE(slv_qhs_camera_cfg, SC8180X_SLAVE_CAMERA_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_clk_ctl, SC8180X_SLAVE_CLK_CTL, 1, 4); +DEFINE_QNODE(slv_qhs_compute_dsp, SC8180X_SLAVE_CDSP_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_cpr_cx, SC8180X_SLAVE_RBCPR_CX_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_cpr_mmcx, SC8180X_SLAVE_RBCPR_MMCX_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_cpr_mx, SC8180X_SLAVE_RBCPR_MX_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_crypto0_cfg, SC8180X_SLAVE_CRYPTO_0_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_ddrss_cfg, SC8180X_SLAVE_CNOC_DDRSS, 1, 4, SC8180X_MASTER_CNOC_DC_NOC); +DEFINE_QNODE(slv_qhs_display_cfg, SC8180X_SLAVE_DISPLAY_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_emac_cfg, SC8180X_SLAVE_EMAC_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_glm, SC8180X_SLAVE_GLM, 1, 4); +DEFINE_QNODE(slv_qhs_gpuss_cfg, SC8180X_SLAVE_GRAPHICS_3D_CFG, 1, 8); +DEFINE_QNODE(slv_qhs_imem_cfg, SC8180X_SLAVE_IMEM_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_ipa, SC8180X_SLAVE_IPA_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_mnoc_cfg, SC8180X_SLAVE_CNOC_MNOC_CFG, 1, 4, SC8180X_MASTER_CNOC_MNOC_CFG); +DEFINE_QNODE(slv_qhs_npu_cfg, SC8180X_SLAVE_NPU_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_pcie0_cfg, SC8180X_SLAVE_PCIE_0_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_pcie1_cfg, SC8180X_SLAVE_PCIE_1_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_pcie2_cfg, SC8180X_SLAVE_PCIE_2_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_pcie3_cfg, SC8180X_SLAVE_PCIE_3_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_pdm, SC8180X_SLAVE_PDM, 1, 4); +DEFINE_QNODE(slv_qhs_pimem_cfg, SC8180X_SLAVE_PIMEM_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_prng, SC8180X_SLAVE_PRNG, 1, 4); +DEFINE_QNODE(slv_qhs_qdss_cfg, SC8180X_SLAVE_QDSS_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_qspi_0, SC8180X_SLAVE_QSPI_0, 1, 4); +DEFINE_QNODE(slv_qhs_qspi_1, SC8180X_SLAVE_QSPI_1, 1, 4); +DEFINE_QNODE(slv_qhs_qupv3_east0, SC8180X_SLAVE_QUP_1, 1, 4); +DEFINE_QNODE(slv_qhs_qupv3_east1, SC8180X_SLAVE_QUP_2, 1, 4); +DEFINE_QNODE(slv_qhs_qupv3_west, SC8180X_SLAVE_QUP_0, 1, 4); +DEFINE_QNODE(slv_qhs_sdc2, SC8180X_SLAVE_SDCC_2, 1, 4); +DEFINE_QNODE(slv_qhs_sdc4, SC8180X_SLAVE_SDCC_4, 1, 4); +DEFINE_QNODE(slv_qhs_security, SC8180X_SLAVE_SECURITY, 1, 4); +DEFINE_QNODE(slv_qhs_snoc_cfg, SC8180X_SLAVE_SNOC_CFG, 1, 4, SC8180X_MASTER_SNOC_CFG); +DEFINE_QNODE(slv_qhs_spss_cfg, SC8180X_SLAVE_SPSS_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_tcsr, SC8180X_SLAVE_TCSR, 1, 4); +DEFINE_QNODE(slv_qhs_tlmm_east, SC8180X_SLAVE_TLMM_EAST, 1, 4); +DEFINE_QNODE(slv_qhs_tlmm_south, SC8180X_SLAVE_TLMM_SOUTH, 1, 4); +DEFINE_QNODE(slv_qhs_tlmm_west, SC8180X_SLAVE_TLMM_WEST, 1, 4); +DEFINE_QNODE(slv_qhs_tsif, SC8180X_SLAVE_TSIF, 1, 4); +DEFINE_QNODE(slv_qhs_ufs_card_cfg, SC8180X_SLAVE_UFS_CARD_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_ufs_mem0_cfg, SC8180X_SLAVE_UFS_MEM_0_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_ufs_mem1_cfg, SC8180X_SLAVE_UFS_MEM_1_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_usb3_0, SC8180X_SLAVE_USB3, 1, 4); +DEFINE_QNODE(slv_qhs_usb3_1, SC8180X_SLAVE_USB3_1, 1, 4); +DEFINE_QNODE(slv_qhs_usb3_2, SC8180X_SLAVE_USB3_2, 1, 4); +DEFINE_QNODE(slv_qhs_venus_cfg, SC8180X_SLAVE_VENUS_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_vsense_ctrl_cfg, SC8180X_SLAVE_VSENSE_CTRL_CFG, 1, 4); +DEFINE_QNODE(slv_srvc_cnoc, SC8180X_SLAVE_SERVICE_CNOC, 1, 4); +DEFINE_QNODE(slv_qhs_gemnoc, SC8180X_SLAVE_GEM_NOC_CFG, 1, 4, SC8180X_MASTER_GEM_NOC_CFG); +DEFINE_QNODE(slv_qhs_llcc, SC8180X_SLAVE_LLCC_CFG, 1, 4); +DEFINE_QNODE(slv_qhs_mdsp_ms_mpu_cfg, SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG, 1, 4); +DEFINE_QNODE(slv_qns_ecc, SC8180X_SLAVE_ECC, 1, 32); +DEFINE_QNODE(slv_qns_gem_noc_snoc, SC8180X_SLAVE_GEM_NOC_SNOC, 1, 8, SC8180X_MASTER_GEM_NOC_SNOC); +DEFINE_QNODE(slv_qns_llcc, SC8180X_SLAVE_LLCC, 8, 16, SC8180X_MASTER_LLCC); +DEFINE_QNODE(slv_srvc_gemnoc, SC8180X_SLAVE_SERVICE_GEM_NOC, 1, 4); +DEFINE_QNODE(slv_srvc_gemnoc1, SC8180X_SLAVE_SERVICE_GEM_NOC_1, 1, 4); +DEFINE_QNODE(slv_ipa_core_slave, SC8180X_SLAVE_IPA_CORE, 1, 8); +DEFINE_QNODE(slv_ebi, SC8180X_SLAVE_EBI_CH0, 8, 4); +DEFINE_QNODE(slv_qns2_mem_noc, SC8180X_SLAVE_MNOC_SF_MEM_NOC, 1, 32, SC8180X_MASTER_MNOC_SF_MEM_NOC); +DEFINE_QNODE(slv_qns_mem_noc_hf, SC8180X_SLAVE_MNOC_HF_MEM_NOC, 2, 32, SC8180X_MASTER_MNOC_HF_MEM_NOC); +DEFINE_QNODE(slv_srvc_mnoc, SC8180X_SLAVE_SERVICE_MNOC, 1, 4); +DEFINE_QNODE(slv_qhs_apss, SC8180X_SLAVE_APPSS, 1, 8); +DEFINE_QNODE(slv_qns_cnoc, SC8180X_SNOC_CNOC_SLV, 1, 8, SC8180X_SNOC_CNOC_MAS); +DEFINE_QNODE(slv_qns_gemnoc_gc, SC8180X_SLAVE_SNOC_GEM_NOC_GC, 1, 8, SC8180X_MASTER_SNOC_GC_MEM_NOC); +DEFINE_QNODE(slv_qns_gemnoc_sf, SC8180X_SLAVE_SNOC_GEM_NOC_SF, 1, 32, SC8180X_MASTER_SNOC_SF_MEM_NOC); +DEFINE_QNODE(slv_qxs_imem, SC8180X_SLAVE_OCIMEM, 1, 8); +DEFINE_QNODE(slv_qxs_pimem, SC8180X_SLAVE_PIMEM, 1, 8); +DEFINE_QNODE(slv_srvc_snoc, SC8180X_SLAVE_SERVICE_SNOC, 1, 4); +DEFINE_QNODE(slv_xs_pcie_0, SC8180X_SLAVE_PCIE_0, 1, 8); +DEFINE_QNODE(slv_xs_pcie_1, SC8180X_SLAVE_PCIE_1, 1, 8); +DEFINE_QNODE(slv_xs_pcie_2, SC8180X_SLAVE_PCIE_2, 1, 8); +DEFINE_QNODE(slv_xs_pcie_3, SC8180X_SLAVE_PCIE_3, 1, 8); +DEFINE_QNODE(slv_xs_qdss_stm, SC8180X_SLAVE_QDSS_STM, 1, 4); +DEFINE_QNODE(slv_xs_sys_tcu_cfg, SC8180X_SLAVE_TCU, 1, 8); + +DEFINE_QBCM(bcm_acv, "ACV", false, &slv_ebi); +DEFINE_QBCM(bcm_mc0, "MC0", false, &slv_ebi); +DEFINE_QBCM(bcm_sh0, "SH0", false, &slv_qns_llcc); +DEFINE_QBCM(bcm_mm0, "MM0", false, &slv_qns_mem_noc_hf); +DEFINE_QBCM(bcm_co0, "CO0", false, &slv_qns_cdsp_mem_noc); +DEFINE_QBCM(bcm_ce0, "CE0", false, &mas_qxm_crypto); +DEFINE_QBCM(bcm_cn0, "CN0", false, &mas_qnm_snoc, &slv_qhs_a1_noc_cfg, &slv_qhs_a2_noc_cfg, &slv_qhs_ahb2phy_refgen_center, &slv_qhs_ahb2phy_refgen_east, &slv_qhs_ahb2phy_refgen_west, &slv_qhs_ahb2phy_south, &slv_qhs_aop, &slv_qhs_aoss, &slv_qhs_camera_cfg, &slv_qhs_clk_ctl, &slv_qhs_compute_dsp, &slv_qhs_cpr_cx, &slv_qhs_cpr_mmcx, &slv_qhs_cpr_mx, &slv_qhs_crypto0_cfg, &slv_qhs_ddrss_cfg, &slv_qhs_display_cfg, &slv_qhs_emac_cfg, &slv_qhs_glm, &slv_qhs_gpuss_cfg, &slv_qhs_imem_cfg, &slv_qhs_ipa, &slv_qhs_mnoc_cfg, &slv_qhs_npu_cfg, &slv_qhs_pcie0_cfg, &slv_qhs_pcie1_cfg, &slv_qhs_pcie2_cfg, &slv_qhs_pcie3_cfg, &slv_qhs_pdm, &slv_qhs_pimem_cfg, &slv_qhs_prng, &slv_qhs_qdss_cfg, &slv_qhs_qspi_0, &slv_qhs_qspi_1, &slv_qhs_qupv3_east0, &slv_qhs_qupv3_east1, &slv_qhs_qupv3_west, &slv_qhs_sdc2, &slv_qhs_sdc4, &slv_qhs_security, &slv_qhs_snoc_cfg, &slv_qhs_spss_cfg, &slv_qhs_tcsr, &slv_qhs_tlmm_east, &slv_qhs_tlmm_south, &slv_qhs_tlmm_west, &slv_qhs_tsif, &slv_qhs_ufs_card_cfg, &slv_qhs_ufs_mem0_cfg, &slv_qhs_ufs_mem1_cfg, &slv_qhs_usb3_0, &slv_qhs_usb3_1, &slv_qhs_usb3_2, &slv_qhs_venus_cfg, &slv_qhs_vsense_ctrl_cfg, &slv_srvc_cnoc); +DEFINE_QBCM(bcm_mm1, "MM1", false, &mas_qxm_camnoc_hf0_uncomp, &mas_qxm_camnoc_hf1_uncomp, &mas_qxm_camnoc_sf_uncomp, &mas_qxm_camnoc_hf0, &mas_qxm_camnoc_hf1, &mas_qxm_mdp0, &mas_qxm_mdp1); +DEFINE_QBCM(bcm_qup0, "QUP0", false, &mas_qhm_qup0, &mas_qhm_qup1, &mas_qhm_qup2); +DEFINE_QBCM(bcm_sh2, "SH2", false, &slv_qns_gem_noc_snoc); +DEFINE_QBCM(bcm_mm2, "MM2", false, &mas_qxm_camnoc_sf, &mas_qxm_rot, &mas_qxm_venus0, &mas_qxm_venus1, &mas_qxm_venus_arm9, &slv_qns2_mem_noc); +DEFINE_QBCM(bcm_sh3, "SH3", false, &mas_acm_apps); +DEFINE_QBCM(bcm_sn0, "SN0", false, &slv_qns_gemnoc_sf); +DEFINE_QBCM(bcm_sn1, "SN1", false, &slv_qxs_imem); +DEFINE_QBCM(bcm_sn2, "SN2", false, &slv_qns_gemnoc_gc); +DEFINE_QBCM(bcm_co2, "CO2", false, &mas_qnm_npu); +DEFINE_QBCM(bcm_ip0, "IP0", false, &slv_ipa_core_slave); +DEFINE_QBCM(bcm_sn3, "SN3", false, &slv_srvc_aggre1_noc, &slv_qns_cnoc); +DEFINE_QBCM(bcm_sn4, "SN4", false, &slv_qxs_pimem); +DEFINE_QBCM(bcm_sn8, "SN8", false, &slv_xs_pcie_0, &slv_xs_pcie_1, &slv_xs_pcie_2, &slv_xs_pcie_3); +DEFINE_QBCM(bcm_sn9, "SN9", false, &mas_qnm_aggre1_noc); +DEFINE_QBCM(bcm_sn11, "SN11", false, &mas_qnm_aggre2_noc); +DEFINE_QBCM(bcm_sn14, "SN14", false, &slv_qns_pcie_mem_noc); +DEFINE_QBCM(bcm_sn15, "SN15", false, &mas_qnm_gemnoc); + +static struct qcom_icc_bcm *aggre1_noc_bcms[] = { + &bcm_sn3, + &bcm_ce0, + &bcm_qup0, +}; + +static struct qcom_icc_bcm *aggre2_noc_bcms[] = { + &bcm_sn14, + &bcm_ce0, + &bcm_qup0, +}; + +static struct qcom_icc_bcm *camnoc_virt_bcms[] = { + &bcm_mm1, +}; + +static struct qcom_icc_bcm *compute_noc_bcms[] = { + &bcm_co0, + &bcm_co2, +}; + +static struct qcom_icc_bcm *config_noc_bcms[] = { + &bcm_cn0, +}; + +static struct qcom_icc_bcm *gem_noc_bcms[] = { + &bcm_sh0, + &bcm_sh2, + &bcm_sh3, +}; + +static struct qcom_icc_bcm *ipa_virt_bcms[] = { + &bcm_ip0, +}; + +static struct qcom_icc_bcm *mc_virt_bcms[] = { + &bcm_mc0, + &bcm_acv, +}; + +static struct qcom_icc_bcm *mmss_noc_bcms[] = { + &bcm_mm0, + &bcm_mm1, + &bcm_mm2, +}; + +static struct qcom_icc_bcm *system_noc_bcms[] = { + &bcm_sn0, + &bcm_sn1, + &bcm_sn2, + &bcm_sn3, + &bcm_sn4, + &bcm_sn8, + &bcm_sn9, + &bcm_sn11, + &bcm_sn15, +}; + +static struct qcom_icc_node *aggre1_noc_nodes[] = { + [MASTER_A1NOC_CFG] = &mas_qhm_a1noc_cfg, + [MASTER_UFS_CARD] = &mas_xm_ufs_card, + [MASTER_UFS_GEN4] = &mas_xm_ufs_g4, + [MASTER_UFS_MEM] = &mas_xm_ufs_mem, + [MASTER_USB3] = &mas_xm_usb3_0, + [MASTER_USB3_1] = &mas_xm_usb3_1, + [MASTER_USB3_2] = &mas_xm_usb3_2, + [A1NOC_SNOC_SLV] = &slv_qns_a1noc_snoc, + [SLAVE_SERVICE_A1NOC] = &slv_srvc_aggre1_noc, +}; + +static struct qcom_icc_node *aggre2_noc_nodes[] = { + [MASTER_A2NOC_CFG] = &mas_qhm_a2noc_cfg, + [MASTER_QDSS_BAM] = &mas_qhm_qdss_bam, + [MASTER_QSPI_0] = &mas_qhm_qspi, + [MASTER_QSPI_1] = &mas_qhm_qspi1, + [MASTER_QUP_0] = &mas_qhm_qup0, + [MASTER_QUP_1] = &mas_qhm_qup1, + [MASTER_QUP_2] = &mas_qhm_qup2, + [MASTER_SENSORS_AHB] = &mas_qhm_sensorss_ahb, + [MASTER_CRYPTO_CORE_0] = &mas_qxm_crypto, + [MASTER_IPA] = &mas_qxm_ipa, + [MASTER_EMAC] = &mas_xm_emac, + [MASTER_PCIE] = &mas_xm_pcie3_0, + [MASTER_PCIE_1] = &mas_xm_pcie3_1, + [MASTER_PCIE_2] = &mas_xm_pcie3_2, + [MASTER_PCIE_3] = &mas_xm_pcie3_3, + [MASTER_QDSS_ETR] = &mas_xm_qdss_etr, + [MASTER_SDCC_2] = &mas_xm_sdc2, + [MASTER_SDCC_4] = &mas_xm_sdc4, + [A2NOC_SNOC_SLV] = &slv_qns_a2noc_snoc, + [SLAVE_ANOC_PCIE_GEM_NOC] = &slv_qns_pcie_mem_noc, + [SLAVE_SERVICE_A2NOC] = &slv_srvc_aggre2_noc, +}; + +static struct qcom_icc_node *camnoc_virt_nodes[] = { + [MASTER_CAMNOC_HF0_UNCOMP] = &mas_qxm_camnoc_hf0_uncomp, + [MASTER_CAMNOC_HF1_UNCOMP] = &mas_qxm_camnoc_hf1_uncomp, + [MASTER_CAMNOC_SF_UNCOMP] = &mas_qxm_camnoc_sf_uncomp, + [SLAVE_CAMNOC_UNCOMP] = &slv_qns_camnoc_uncomp, +}; + +static struct qcom_icc_node *compute_noc_nodes[] = { + [MASTER_NPU] = &mas_qnm_npu, + [SLAVE_CDSP_MEM_NOC] = &slv_qns_cdsp_mem_noc, +}; + +static struct qcom_icc_node *config_noc_nodes[] = { + [SNOC_CNOC_MAS] = &mas_qnm_snoc, + [SLAVE_A1NOC_CFG] = &slv_qhs_a1_noc_cfg, + [SLAVE_A2NOC_CFG] = &slv_qhs_a2_noc_cfg, + [SLAVE_AHB2PHY_CENTER] = &slv_qhs_ahb2phy_refgen_center, + [SLAVE_AHB2PHY_EAST] = &slv_qhs_ahb2phy_refgen_east, + [SLAVE_AHB2PHY_WEST] = &slv_qhs_ahb2phy_refgen_west, + [SLAVE_AHB2PHY_SOUTH] = &slv_qhs_ahb2phy_south, + [SLAVE_AOP] = &slv_qhs_aop, + [SLAVE_AOSS] = &slv_qhs_aoss, + [SLAVE_CAMERA_CFG] = &slv_qhs_camera_cfg, + [SLAVE_CLK_CTL] = &slv_qhs_clk_ctl, + [SLAVE_CDSP_CFG] = &slv_qhs_compute_dsp, + [SLAVE_RBCPR_CX_CFG] = &slv_qhs_cpr_cx, + [SLAVE_RBCPR_MMCX_CFG] = &slv_qhs_cpr_mmcx, + [SLAVE_RBCPR_MX_CFG] = &slv_qhs_cpr_mx, + [SLAVE_CRYPTO_0_CFG] = &slv_qhs_crypto0_cfg, + [SLAVE_CNOC_DDRSS] = &slv_qhs_ddrss_cfg, + [SLAVE_DISPLAY_CFG] = &slv_qhs_display_cfg, + [SLAVE_EMAC_CFG] = &slv_qhs_emac_cfg, + [SLAVE_GLM] = &slv_qhs_glm, + [SLAVE_GRAPHICS_3D_CFG] = &slv_qhs_gpuss_cfg, + [SLAVE_IMEM_CFG] = &slv_qhs_imem_cfg, + [SLAVE_IPA_CFG] = &slv_qhs_ipa, + [SLAVE_CNOC_MNOC_CFG] = &slv_qhs_mnoc_cfg, + [SLAVE_NPU_CFG] = &slv_qhs_npu_cfg, + [SLAVE_PCIE_0_CFG] = &slv_qhs_pcie0_cfg, + [SLAVE_PCIE_1_CFG] = &slv_qhs_pcie1_cfg, + [SLAVE_PCIE_2_CFG] = &slv_qhs_pcie2_cfg, + [SLAVE_PCIE_3_CFG] = &slv_qhs_pcie3_cfg, + [SLAVE_PDM] = &slv_qhs_pdm, + [SLAVE_PIMEM_CFG] = &slv_qhs_pimem_cfg, + [SLAVE_PRNG] = &slv_qhs_prng, + [SLAVE_QDSS_CFG] = &slv_qhs_qdss_cfg, + [SLAVE_QSPI_0] = &slv_qhs_qspi_0, + [SLAVE_QSPI_1] = &slv_qhs_qspi_1, + [SLAVE_QUP_1] = &slv_qhs_qupv3_east0, + [SLAVE_QUP_2] = &slv_qhs_qupv3_east1, + [SLAVE_QUP_0] = &slv_qhs_qupv3_west, + [SLAVE_SDCC_2] = &slv_qhs_sdc2, + [SLAVE_SDCC_4] = &slv_qhs_sdc4, + [SLAVE_SECURITY] = &slv_qhs_security, + [SLAVE_SNOC_CFG] = &slv_qhs_snoc_cfg, + [SLAVE_SPSS_CFG] = &slv_qhs_spss_cfg, + [SLAVE_TCSR] = &slv_qhs_tcsr, + [SLAVE_TLMM_EAST] = &slv_qhs_tlmm_east, + [SLAVE_TLMM_SOUTH] = &slv_qhs_tlmm_south, + [SLAVE_TLMM_WEST] = &slv_qhs_tlmm_west, + [SLAVE_TSIF] = &slv_qhs_tsif, + [SLAVE_UFS_CARD_CFG] = &slv_qhs_ufs_card_cfg, + [SLAVE_UFS_MEM_0_CFG] = &slv_qhs_ufs_mem0_cfg, + [SLAVE_UFS_MEM_1_CFG] = &slv_qhs_ufs_mem1_cfg, + [SLAVE_USB3] = &slv_qhs_usb3_0, + [SLAVE_USB3_1] = &slv_qhs_usb3_1, + [SLAVE_USB3_2] = &slv_qhs_usb3_2, + [SLAVE_VENUS_CFG] = &slv_qhs_venus_cfg, + [SLAVE_VSENSE_CTRL_CFG] = &slv_qhs_vsense_ctrl_cfg, + [SLAVE_SERVICE_CNOC] = &slv_srvc_cnoc, +}; + +static struct qcom_icc_node *dc_noc_nodes[] = { + [MASTER_CNOC_DC_NOC] = &mas_qhm_cnoc_dc_noc, + [SLAVE_GEM_NOC_CFG] = &slv_qhs_gemnoc, + [SLAVE_LLCC_CFG] = &slv_qhs_llcc, +}; + +static struct qcom_icc_node *gem_noc_nodes[] = { + [MASTER_AMPSS_M0] = &mas_acm_apps, + [MASTER_GPU_TCU] = &mas_acm_gpu_tcu, + [MASTER_SYS_TCU] = &mas_acm_sys_tcu, + [MASTER_GEM_NOC_CFG] = &mas_qhm_gemnoc_cfg, + [MASTER_COMPUTE_NOC] = &mas_qnm_cmpnoc, + [MASTER_GRAPHICS_3D] = &mas_qnm_gpu, + [MASTER_MNOC_HF_MEM_NOC] = &mas_qnm_mnoc_hf, + [MASTER_MNOC_SF_MEM_NOC] = &mas_qnm_mnoc_sf, + [MASTER_GEM_NOC_PCIE_SNOC] = &mas_qnm_pcie, + [MASTER_SNOC_GC_MEM_NOC] = &mas_qnm_snoc_gc, + [MASTER_SNOC_SF_MEM_NOC] = &mas_qnm_snoc_sf, + [MASTER_ECC] = &mas_qxm_ecc, + [SLAVE_MSS_PROC_MS_MPU_CFG] = &slv_qhs_mdsp_ms_mpu_cfg, + [SLAVE_ECC] = &slv_qns_ecc, + [SLAVE_GEM_NOC_SNOC] = &slv_qns_gem_noc_snoc, + [SLAVE_LLCC] = &slv_qns_llcc, + [SLAVE_SERVICE_GEM_NOC] = &slv_srvc_gemnoc, + [SLAVE_SERVICE_GEM_NOC_1] = &slv_srvc_gemnoc1, +}; + +static struct qcom_icc_node *ipa_virt_nodes[] = { + [MASTER_IPA_CORE] = &mas_ipa_core_master, + [SLAVE_IPA_CORE] = &slv_ipa_core_slave, +}; + +static struct qcom_icc_node *mc_virt_nodes[] = { + [MASTER_LLCC] = &mas_llcc_mc, + [SLAVE_EBI_CH0] = &slv_ebi, +}; + +static struct qcom_icc_node *mmss_noc_nodes[] = { + [MASTER_CNOC_MNOC_CFG] = &mas_qhm_mnoc_cfg, + [MASTER_CAMNOC_HF0] = &mas_qxm_camnoc_hf0, + [MASTER_CAMNOC_HF1] = &mas_qxm_camnoc_hf1, + [MASTER_CAMNOC_SF] = &mas_qxm_camnoc_sf, + [MASTER_MDP_PORT0] = &mas_qxm_mdp0, + [MASTER_MDP_PORT1] = &mas_qxm_mdp1, + [MASTER_ROTATOR] = &mas_qxm_rot, + [MASTER_VIDEO_P0] = &mas_qxm_venus0, + [MASTER_VIDEO_P1] = &mas_qxm_venus1, + [MASTER_VIDEO_PROC] = &mas_qxm_venus_arm9, + [SLAVE_MNOC_SF_MEM_NOC] = &slv_qns2_mem_noc, + [SLAVE_MNOC_HF_MEM_NOC] = &slv_qns_mem_noc_hf, + [SLAVE_SERVICE_MNOC] = &slv_srvc_mnoc, +}; + +static struct qcom_icc_node *system_noc_nodes[] = { + [MASTER_SNOC_CFG] = &mas_qhm_snoc_cfg, + [A1NOC_SNOC_MAS] = &mas_qnm_aggre1_noc, + [A2NOC_SNOC_MAS] = &mas_qnm_aggre2_noc, + [MASTER_GEM_NOC_SNOC] = &mas_qnm_gemnoc, + [MASTER_PIMEM] = &mas_qxm_pimem, + [MASTER_GIC] = &mas_xm_gic, + [SLAVE_APPSS] = &slv_qhs_apss, + [SNOC_CNOC_SLV] = &slv_qns_cnoc, + [SLAVE_SNOC_GEM_NOC_GC] = &slv_qns_gemnoc_gc, + [SLAVE_SNOC_GEM_NOC_SF] = &slv_qns_gemnoc_sf, + [SLAVE_OCIMEM] = &slv_qxs_imem, + [SLAVE_PIMEM] = &slv_qxs_pimem, + [SLAVE_SERVICE_SNOC] = &slv_srvc_snoc, + [SLAVE_QDSS_STM] = &slv_xs_qdss_stm, + [SLAVE_TCU] = &slv_xs_sys_tcu_cfg, +}; + +static const struct qcom_icc_desc sc8180x_aggre1_noc = { + .nodes = aggre1_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre1_noc_nodes), + .bcms = aggre1_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre1_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_aggre2_noc = { + .nodes = aggre2_noc_nodes, + .num_nodes = ARRAY_SIZE(aggre2_noc_nodes), + .bcms = aggre2_noc_bcms, + .num_bcms = ARRAY_SIZE(aggre2_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_camnoc_virt = { + .nodes = camnoc_virt_nodes, + .num_nodes = ARRAY_SIZE(camnoc_virt_nodes), + .bcms = camnoc_virt_bcms, + .num_bcms = ARRAY_SIZE(camnoc_virt_bcms), +}; + +static const struct qcom_icc_desc sc8180x_compute_noc = { + .nodes = compute_noc_nodes, + .num_nodes = ARRAY_SIZE(compute_noc_nodes), + .bcms = compute_noc_bcms, + .num_bcms = ARRAY_SIZE(compute_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_config_noc = { + .nodes = config_noc_nodes, + .num_nodes = ARRAY_SIZE(config_noc_nodes), + .bcms = config_noc_bcms, + .num_bcms = ARRAY_SIZE(config_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_dc_noc = { + .nodes = dc_noc_nodes, + .num_nodes = ARRAY_SIZE(dc_noc_nodes), +}; + +static const struct qcom_icc_desc sc8180x_gem_noc = { + .nodes = gem_noc_nodes, + .num_nodes = ARRAY_SIZE(gem_noc_nodes), + .bcms = gem_noc_bcms, + .num_bcms = ARRAY_SIZE(gem_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_ipa_virt = { + .nodes = ipa_virt_nodes, + .num_nodes = ARRAY_SIZE(ipa_virt_nodes), + .bcms = ipa_virt_bcms, + .num_bcms = ARRAY_SIZE(ipa_virt_bcms), +}; + +static const struct qcom_icc_desc sc8180x_mc_virt = { + .nodes = mc_virt_nodes, + .num_nodes = ARRAY_SIZE(mc_virt_nodes), + .bcms = mc_virt_bcms, + .num_bcms = ARRAY_SIZE(mc_virt_bcms), +}; + +static const struct qcom_icc_desc sc8180x_mmss_noc = { + .nodes = mmss_noc_nodes, + .num_nodes = ARRAY_SIZE(mmss_noc_nodes), + .bcms = mmss_noc_bcms, + .num_bcms = ARRAY_SIZE(mmss_noc_bcms), +}; + +static const struct qcom_icc_desc sc8180x_system_noc = { + .nodes = system_noc_nodes, + .num_nodes = ARRAY_SIZE(system_noc_nodes), + .bcms = system_noc_bcms, + .num_bcms = ARRAY_SIZE(system_noc_bcms), +}; + +static int qnoc_probe(struct platform_device *pdev) +{ + const struct qcom_icc_desc *desc; + struct icc_onecell_data *data; + struct icc_provider *provider; + struct qcom_icc_node **qnodes; + struct qcom_icc_provider *qp; + struct icc_node *node; + size_t num_nodes, i; + int ret; + + desc = device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + qnodes = desc->nodes; + num_nodes = desc->num_nodes; + + qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL); + if (!qp) + return -ENOMEM; + + data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL); + if (!data) + return -ENOMEM; + + provider = &qp->provider; + provider->dev = &pdev->dev; + provider->set = qcom_icc_set; + provider->pre_aggregate = qcom_icc_pre_aggregate; + provider->aggregate = qcom_icc_aggregate; + provider->xlate = of_icc_xlate_onecell; + INIT_LIST_HEAD(&provider->nodes); + provider->data = data; + + qp->dev = &pdev->dev; + qp->bcms = desc->bcms; + qp->num_bcms = desc->num_bcms; + + qp->voter = of_bcm_voter_get(qp->dev, NULL); + if (IS_ERR(qp->voter)) + return PTR_ERR(qp->voter); + + ret = icc_provider_add(provider); + if (ret) { + dev_err(&pdev->dev, "error adding interconnect provider\n"); + return ret; + } + + for (i = 0; i < qp->num_bcms; i++) + qcom_icc_bcm_init(qp->bcms[i], &pdev->dev); + + for (i = 0; i < num_nodes; i++) { + size_t j; + + if (!qnodes[i]) + continue; + + node = icc_node_create(qnodes[i]->id); + if (IS_ERR(node)) { + ret = PTR_ERR(node); + goto err; + } + + node->name = qnodes[i]->name; + node->data = qnodes[i]; + icc_node_add(node, provider); + + for (j = 0; j < qnodes[i]->num_links; j++) + icc_link_create(node, qnodes[i]->links[j]); + + data->nodes[i] = node; + } + data->num_nodes = num_nodes; + + platform_set_drvdata(pdev, qp); + + return 0; +err: + icc_nodes_remove(provider); + icc_provider_del(provider); + return ret; +} + +static int qnoc_remove(struct platform_device *pdev) +{ + struct qcom_icc_provider *qp = platform_get_drvdata(pdev); + + icc_nodes_remove(&qp->provider); + return icc_provider_del(&qp->provider); +} + +static const struct of_device_id qnoc_of_match[] = { + { .compatible = "qcom,sc8180x-aggre1-noc", .data = &sc8180x_aggre1_noc }, + { .compatible = "qcom,sc8180x-aggre2-noc", .data = &sc8180x_aggre2_noc }, + { .compatible = "qcom,sc8180x-camnoc-virt", .data = &sc8180x_camnoc_virt }, + { .compatible = "qcom,sc8180x-compute-noc", .data = &sc8180x_compute_noc, }, + { .compatible = "qcom,sc8180x-config-noc", .data = &sc8180x_config_noc }, + { .compatible = "qcom,sc8180x-dc-noc", .data = &sc8180x_dc_noc }, + { .compatible = "qcom,sc8180x-gem-noc", .data = &sc8180x_gem_noc }, + { .compatible = "qcom,sc8180x-ipa-virt", .data = &sc8180x_ipa_virt }, + { .compatible = "qcom,sc8180x-mc-virt", .data = &sc8180x_mc_virt }, + { .compatible = "qcom,sc8180x-mmss-noc", .data = &sc8180x_mmss_noc }, + { .compatible = "qcom,sc8180x-system-noc", .data = &sc8180x_system_noc }, + { } +}; +MODULE_DEVICE_TABLE(of, qnoc_of_match); + +static struct platform_driver qnoc_driver = { + .probe = qnoc_probe, + .remove = qnoc_remove, + .driver = { + .name = "qnoc-sc8180x", + .of_match_table = qnoc_of_match, + .sync_state = icc_sync_state, + }, +}; +module_platform_driver(qnoc_driver); + +MODULE_DESCRIPTION("Qualcomm sc8180x NoC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/interconnect/qcom/sc8180x.h b/drivers/interconnect/qcom/sc8180x.h new file mode 100644 index 000000000000..fed2dc2d4acb --- /dev/null +++ b/drivers/interconnect/qcom/sc8180x.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Qualcomm #define SC8180X interconnect IDs + * + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __DRIVERS_INTERCONNECT_QCOM_SC8180X_H +#define __DRIVERS_INTERCONNECT_QCOM_SC8180X_H + +#define SC8180X_MASTER_A1NOC_CFG 1 +#define SC8180X_MASTER_UFS_CARD 2 +#define SC8180X_MASTER_UFS_GEN4 3 +#define SC8180X_MASTER_UFS_MEM 4 +#define SC8180X_MASTER_USB3 5 +#define SC8180X_MASTER_USB3_1 6 +#define SC8180X_MASTER_USB3_2 7 +#define SC8180X_MASTER_A2NOC_CFG 8 +#define SC8180X_MASTER_QDSS_BAM 9 +#define SC8180X_MASTER_QSPI_0 10 +#define SC8180X_MASTER_QSPI_1 11 +#define SC8180X_MASTER_QUP_0 12 +#define SC8180X_MASTER_QUP_1 13 +#define SC8180X_MASTER_QUP_2 14 +#define SC8180X_MASTER_SENSORS_AHB 15 +#define SC8180X_MASTER_CRYPTO_CORE_0 16 +#define SC8180X_MASTER_IPA 17 +#define SC8180X_MASTER_EMAC 18 +#define SC8180X_MASTER_PCIE 19 +#define SC8180X_MASTER_PCIE_1 20 +#define SC8180X_MASTER_PCIE_2 21 +#define SC8180X_MASTER_PCIE_3 22 +#define SC8180X_MASTER_QDSS_ETR 23 +#define SC8180X_MASTER_SDCC_2 24 +#define SC8180X_MASTER_SDCC_4 25 +#define SC8180X_MASTER_CAMNOC_HF0_UNCOMP 26 +#define SC8180X_MASTER_CAMNOC_HF1_UNCOMP 27 +#define SC8180X_MASTER_CAMNOC_SF_UNCOMP 28 +#define SC8180X_MASTER_NPU 29 +#define SC8180X_SNOC_CNOC_MAS 30 +#define SC8180X_MASTER_CNOC_DC_NOC 31 +#define SC8180X_MASTER_AMPSS_M0 32 +#define SC8180X_MASTER_GPU_TCU 33 +#define SC8180X_MASTER_SYS_TCU 34 +#define SC8180X_MASTER_GEM_NOC_CFG 35 +#define SC8180X_MASTER_COMPUTE_NOC 36 +#define SC8180X_MASTER_GRAPHICS_3D 37 +#define SC8180X_MASTER_MNOC_HF_MEM_NOC 38 +#define SC8180X_MASTER_MNOC_SF_MEM_NOC 39 +#define SC8180X_MASTER_GEM_NOC_PCIE_SNOC 40 +#define SC8180X_MASTER_SNOC_GC_MEM_NOC 41 +#define SC8180X_MASTER_SNOC_SF_MEM_NOC 42 +#define SC8180X_MASTER_ECC 43 +#define SC8180X_MASTER_IPA_CORE 44 +#define SC8180X_MASTER_LLCC 45 +#define SC8180X_MASTER_CNOC_MNOC_CFG 46 +#define SC8180X_MASTER_CAMNOC_HF0 47 +#define SC8180X_MASTER_CAMNOC_HF1 48 +#define SC8180X_MASTER_CAMNOC_SF 49 +#define SC8180X_MASTER_MDP_PORT0 50 +#define SC8180X_MASTER_MDP_PORT1 51 +#define SC8180X_MASTER_ROTATOR 52 +#define SC8180X_MASTER_VIDEO_P0 53 +#define SC8180X_MASTER_VIDEO_P1 54 +#define SC8180X_MASTER_VIDEO_PROC 55 +#define SC8180X_MASTER_SNOC_CFG 56 +#define SC8180X_A1NOC_SNOC_MAS 57 +#define SC8180X_A2NOC_SNOC_MAS 58 +#define SC8180X_MASTER_GEM_NOC_SNOC 59 +#define SC8180X_MASTER_PIMEM 60 +#define SC8180X_MASTER_GIC 61 +#define SC8180X_MASTER_MNOC_HF_MEM_NOC_DISPLAY 62 +#define SC8180X_MASTER_MNOC_SF_MEM_NOC_DISPLAY 63 +#define SC8180X_MASTER_LLCC_DISPLAY 64 +#define SC8180X_MASTER_MDP_PORT0_DISPLAY 65 +#define SC8180X_MASTER_MDP_PORT1_DISPLAY 66 +#define SC8180X_MASTER_ROTATOR_DISPLAY 67 +#define SC8180X_A1NOC_SNOC_SLV 68 +#define SC8180X_SLAVE_SERVICE_A1NOC 69 +#define SC8180X_A2NOC_SNOC_SLV 70 +#define SC8180X_SLAVE_ANOC_PCIE_GEM_NOC 71 +#define SC8180X_SLAVE_SERVICE_A2NOC 72 +#define SC8180X_SLAVE_CAMNOC_UNCOMP 73 +#define SC8180X_SLAVE_CDSP_MEM_NOC 74 +#define SC8180X_SLAVE_A1NOC_CFG 75 +#define SC8180X_SLAVE_A2NOC_CFG 76 +#define SC8180X_SLAVE_AHB2PHY_CENTER 77 +#define SC8180X_SLAVE_AHB2PHY_EAST 78 +#define SC8180X_SLAVE_AHB2PHY_WEST 79 +#define SC8180X_SLAVE_AHB2PHY_SOUTH 80 +#define SC8180X_SLAVE_AOP 81 +#define SC8180X_SLAVE_AOSS 82 +#define SC8180X_SLAVE_CAMERA_CFG 83 +#define SC8180X_SLAVE_CLK_CTL 84 +#define SC8180X_SLAVE_CDSP_CFG 85 +#define SC8180X_SLAVE_RBCPR_CX_CFG 86 +#define SC8180X_SLAVE_RBCPR_MMCX_CFG 87 +#define SC8180X_SLAVE_RBCPR_MX_CFG 88 +#define SC8180X_SLAVE_CRYPTO_0_CFG 89 +#define SC8180X_SLAVE_CNOC_DDRSS 90 +#define SC8180X_SLAVE_DISPLAY_CFG 91 +#define SC8180X_SLAVE_EMAC_CFG 92 +#define SC8180X_SLAVE_GLM 93 +#define SC8180X_SLAVE_GRAPHICS_3D_CFG 94 +#define SC8180X_SLAVE_IMEM_CFG 95 +#define SC8180X_SLAVE_IPA_CFG 96 +#define SC8180X_SLAVE_CNOC_MNOC_CFG 97 +#define SC8180X_SLAVE_NPU_CFG 98 +#define SC8180X_SLAVE_PCIE_0_CFG 99 +#define SC8180X_SLAVE_PCIE_1_CFG 100 +#define SC8180X_SLAVE_PCIE_2_CFG 101 +#define SC8180X_SLAVE_PCIE_3_CFG 102 +#define SC8180X_SLAVE_PDM 103 +#define SC8180X_SLAVE_PIMEM_CFG 104 +#define SC8180X_SLAVE_PRNG 105 +#define SC8180X_SLAVE_QDSS_CFG 106 +#define SC8180X_SLAVE_QSPI_0 107 +#define SC8180X_SLAVE_QSPI_1 108 +#define SC8180X_SLAVE_QUP_1 109 +#define SC8180X_SLAVE_QUP_2 110 +#define SC8180X_SLAVE_QUP_0 111 +#define SC8180X_SLAVE_SDCC_2 112 +#define SC8180X_SLAVE_SDCC_4 113 +#define SC8180X_SLAVE_SECURITY 114 +#define SC8180X_SLAVE_SNOC_CFG 115 +#define SC8180X_SLAVE_SPSS_CFG 116 +#define SC8180X_SLAVE_TCSR 117 +#define SC8180X_SLAVE_TLMM_EAST 118 +#define SC8180X_SLAVE_TLMM_SOUTH 119 +#define SC8180X_SLAVE_TLMM_WEST 120 +#define SC8180X_SLAVE_TSIF 121 +#define SC8180X_SLAVE_UFS_CARD_CFG 122 +#define SC8180X_SLAVE_UFS_MEM_0_CFG 123 +#define SC8180X_SLAVE_UFS_MEM_1_CFG 124 +#define SC8180X_SLAVE_USB3 125 +#define SC8180X_SLAVE_USB3_1 126 +#define SC8180X_SLAVE_USB3_2 127 +#define SC8180X_SLAVE_VENUS_CFG 128 +#define SC8180X_SLAVE_VSENSE_CTRL_CFG 129 +#define SC8180X_SLAVE_SERVICE_CNOC 130 +#define SC8180X_SLAVE_GEM_NOC_CFG 131 +#define SC8180X_SLAVE_LLCC_CFG 132 +#define SC8180X_SLAVE_MSS_PROC_MS_MPU_CFG 133 +#define SC8180X_SLAVE_ECC 134 +#define SC8180X_SLAVE_GEM_NOC_SNOC 135 +#define SC8180X_SLAVE_LLCC 136 +#define SC8180X_SLAVE_SERVICE_GEM_NOC 137 +#define SC8180X_SLAVE_SERVICE_GEM_NOC_1 138 +#define SC8180X_SLAVE_IPA_CORE 139 +#define SC8180X_SLAVE_EBI_CH0 140 +#define SC8180X_SLAVE_MNOC_SF_MEM_NOC 141 +#define SC8180X_SLAVE_MNOC_HF_MEM_NOC 142 +#define SC8180X_SLAVE_SERVICE_MNOC 143 +#define SC8180X_SLAVE_APPSS 144 +#define SC8180X_SNOC_CNOC_SLV 145 +#define SC8180X_SLAVE_SNOC_GEM_NOC_GC 146 +#define SC8180X_SLAVE_SNOC_GEM_NOC_SF 147 +#define SC8180X_SLAVE_OCIMEM 148 +#define SC8180X_SLAVE_PIMEM 149 +#define SC8180X_SLAVE_SERVICE_SNOC 150 +#define SC8180X_SLAVE_PCIE_0 151 +#define SC8180X_SLAVE_PCIE_1 152 +#define SC8180X_SLAVE_PCIE_2 153 +#define SC8180X_SLAVE_PCIE_3 154 +#define SC8180X_SLAVE_QDSS_STM 155 +#define SC8180X_SLAVE_TCU 156 +#define SC8180X_SLAVE_LLCC_DISPLAY 157 +#define SC8180X_SLAVE_EBI_CH0_DISPLAY 158 +#define SC8180X_SLAVE_MNOC_SF_MEM_NOC_DISPLAY 159 +#define SC8180X_SLAVE_MNOC_HF_MEM_NOC_DISPLAY 160 + +#endif -- cgit v1.2.3 From 13fa44c0b6bfbbf15e17ca90b4ae378ca072417d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 24 Jul 2021 19:58:33 -0700 Subject: dt-bindings: interconnect: Add SC8180x to OSM L3 DT binding The Qualcomm SC8180x has an OSM L3, add compatible for this. Signed-off-by: Bjorn Andersson Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210725025834.3941777-1-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml index d6a95c3cb26f..e701524ee811 100644 --- a/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml +++ b/Documentation/devicetree/bindings/interconnect/qcom,osm-l3.yaml @@ -18,6 +18,7 @@ properties: compatible: enum: - qcom,sc7180-osm-l3 + - qcom,sc8180x-osm-l3 - qcom,sdm845-osm-l3 - qcom,sm8150-osm-l3 - qcom,sm8250-epss-l3 -- cgit v1.2.3 From ffef0b13bf3ededa07570a2926d13a741a1d5272 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 24 Jul 2021 19:58:34 -0700 Subject: interconnect: qcom: osm-l3: Add sc8180x support Add support for the Qualcomm SC8180x platform to the OSM L3 driver. Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20210725025834.3941777-2-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/osm-l3.c | 18 ++++++++++++++++++ drivers/interconnect/qcom/sc8180x.h | 2 ++ 2 files changed, 20 insertions(+) diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 695f28789e98..13e41b932567 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -15,6 +15,7 @@ #include #include "sc7180.h" +#include "sc8180x.h" #include "sdm845.h" #include "sm8150.h" #include "sm8250.h" @@ -113,6 +114,22 @@ static const struct qcom_icc_desc sc7180_icc_osm_l3 = { .reg_perf_state = OSM_REG_PERF_STATE, }; +DEFINE_QNODE(sc8180x_osm_apps_l3, SC8180X_MASTER_OSM_L3_APPS, 32, SC8180X_SLAVE_OSM_L3); +DEFINE_QNODE(sc8180x_osm_l3, SC8180X_SLAVE_OSM_L3, 32); + +static const struct qcom_icc_node *sc8180x_osm_l3_nodes[] = { + [MASTER_OSM_L3_APPS] = &sc8180x_osm_apps_l3, + [SLAVE_OSM_L3] = &sc8180x_osm_l3, +}; + +static const struct qcom_icc_desc sc8180x_icc_osm_l3 = { + .nodes = sc8180x_osm_l3_nodes, + .num_nodes = ARRAY_SIZE(sc8180x_osm_l3_nodes), + .lut_row_size = OSM_LUT_ROW_SIZE, + .reg_freq_lut = OSM_REG_FREQ_LUT, + .reg_perf_state = OSM_REG_PERF_STATE, +}; + DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3); DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32); @@ -311,6 +328,7 @@ static const struct of_device_id osm_l3_of_match[] = { { .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 }, { .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 }, { .compatible = "qcom,sm8150-osm-l3", .data = &sm8150_icc_osm_l3 }, + { .compatible = "qcom,sc8180x-osm-l3", .data = &sc8180x_icc_osm_l3 }, { .compatible = "qcom,sm8250-epss-l3", .data = &sm8250_icc_epss_l3 }, { } }; diff --git a/drivers/interconnect/qcom/sc8180x.h b/drivers/interconnect/qcom/sc8180x.h index fed2dc2d4acb..e70cf7032f80 100644 --- a/drivers/interconnect/qcom/sc8180x.h +++ b/drivers/interconnect/qcom/sc8180x.h @@ -168,5 +168,7 @@ #define SC8180X_SLAVE_EBI_CH0_DISPLAY 158 #define SC8180X_SLAVE_MNOC_SF_MEM_NOC_DISPLAY 159 #define SC8180X_SLAVE_MNOC_HF_MEM_NOC_DISPLAY 160 +#define SC8180X_MASTER_OSM_L3_APPS 161 +#define SC8180X_SLAVE_OSM_L3 162 #endif -- cgit v1.2.3 From 8bf5d31c4f06d806ae24a3ba998a2f4eaccfa7c1 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 24 Jul 2021 20:14:14 -0700 Subject: interconnect: qcom: osm-l3: Use driver-specific naming In situations were the developer screws up by e.g. not giving the OSM nodes unique identifiers the interconnect framework might mix up nodes between the OSM L3 provider and e.g. the RPMh provider. The resulting callstack contains "qcom_icc_set", which is not unique to the OSM L3 provider driver. Once the faulting qcom_icc_set() is identified it's further confusing that "qcom_icc_node" is different between the different drivers. To avoid this confusion, rename the node struct and the setter in the OSM L3 driver to include "osm_l3" in their names. Signed-off-by: Bjorn Andersson Tested-by: Steev Klimaszewski Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20210725031414.3961227-1-bjorn.andersson@linaro.org Signed-off-by: Georgi Djakov --- drivers/interconnect/qcom/osm-l3.c | 46 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/interconnect/qcom/osm-l3.c b/drivers/interconnect/qcom/osm-l3.c index 13e41b932567..c7af143980de 100644 --- a/drivers/interconnect/qcom/osm-l3.c +++ b/drivers/interconnect/qcom/osm-l3.c @@ -38,7 +38,7 @@ #define OSM_L3_MAX_LINKS 1 -#define to_qcom_provider(_provider) \ +#define to_osm_l3_provider(_provider) \ container_of(_provider, struct qcom_osm_l3_icc_provider, provider) struct qcom_osm_l3_icc_provider { @@ -50,14 +50,14 @@ struct qcom_osm_l3_icc_provider { }; /** - * struct qcom_icc_node - Qualcomm specific interconnect nodes + * struct qcom_osm_l3_node - Qualcomm specific interconnect nodes * @name: the node name used in debugfs * @links: an array of nodes where we can go next while traversing * @id: a unique node identifier * @num_links: the total number of @links * @buswidth: width of the interconnect between a node and the bus */ -struct qcom_icc_node { +struct qcom_osm_l3_node { const char *name; u16 links[OSM_L3_MAX_LINKS]; u16 id; @@ -65,8 +65,8 @@ struct qcom_icc_node { u16 buswidth; }; -struct qcom_icc_desc { - const struct qcom_icc_node **nodes; +struct qcom_osm_l3_desc { + const struct qcom_osm_l3_node **nodes; size_t num_nodes; unsigned int lut_row_size; unsigned int reg_freq_lut; @@ -74,7 +74,7 @@ struct qcom_icc_desc { }; #define DEFINE_QNODE(_name, _id, _buswidth, ...) \ - static const struct qcom_icc_node _name = { \ + static const struct qcom_osm_l3_node _name = { \ .name = #_name, \ .id = _id, \ .buswidth = _buswidth, \ @@ -85,12 +85,12 @@ struct qcom_icc_desc { DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3); DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16); -static const struct qcom_icc_node *sdm845_osm_l3_nodes[] = { +static const struct qcom_osm_l3_node *sdm845_osm_l3_nodes[] = { [MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3, [SLAVE_OSM_L3] = &sdm845_osm_l3, }; -static const struct qcom_icc_desc sdm845_icc_osm_l3 = { +static const struct qcom_osm_l3_desc sdm845_icc_osm_l3 = { .nodes = sdm845_osm_l3_nodes, .num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes), .lut_row_size = OSM_LUT_ROW_SIZE, @@ -101,12 +101,12 @@ static const struct qcom_icc_desc sdm845_icc_osm_l3 = { DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3); DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16); -static const struct qcom_icc_node *sc7180_osm_l3_nodes[] = { +static const struct qcom_osm_l3_node *sc7180_osm_l3_nodes[] = { [MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3, [SLAVE_OSM_L3] = &sc7180_osm_l3, }; -static const struct qcom_icc_desc sc7180_icc_osm_l3 = { +static const struct qcom_osm_l3_desc sc7180_icc_osm_l3 = { .nodes = sc7180_osm_l3_nodes, .num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes), .lut_row_size = OSM_LUT_ROW_SIZE, @@ -117,12 +117,12 @@ static const struct qcom_icc_desc sc7180_icc_osm_l3 = { DEFINE_QNODE(sc8180x_osm_apps_l3, SC8180X_MASTER_OSM_L3_APPS, 32, SC8180X_SLAVE_OSM_L3); DEFINE_QNODE(sc8180x_osm_l3, SC8180X_SLAVE_OSM_L3, 32); -static const struct qcom_icc_node *sc8180x_osm_l3_nodes[] = { +static const struct qcom_osm_l3_node *sc8180x_osm_l3_nodes[] = { [MASTER_OSM_L3_APPS] = &sc8180x_osm_apps_l3, [SLAVE_OSM_L3] = &sc8180x_osm_l3, }; -static const struct qcom_icc_desc sc8180x_icc_osm_l3 = { +static const struct qcom_osm_l3_desc sc8180x_icc_osm_l3 = { .nodes = sc8180x_osm_l3_nodes, .num_nodes = ARRAY_SIZE(sc8180x_osm_l3_nodes), .lut_row_size = OSM_LUT_ROW_SIZE, @@ -133,12 +133,12 @@ static const struct qcom_icc_desc sc8180x_icc_osm_l3 = { DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3); DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32); -static const struct qcom_icc_node *sm8150_osm_l3_nodes[] = { +static const struct qcom_osm_l3_node *sm8150_osm_l3_nodes[] = { [MASTER_OSM_L3_APPS] = &sm8150_osm_apps_l3, [SLAVE_OSM_L3] = &sm8150_osm_l3, }; -static const struct qcom_icc_desc sm8150_icc_osm_l3 = { +static const struct qcom_osm_l3_desc sm8150_icc_osm_l3 = { .nodes = sm8150_osm_l3_nodes, .num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes), .lut_row_size = OSM_LUT_ROW_SIZE, @@ -149,12 +149,12 @@ static const struct qcom_icc_desc sm8150_icc_osm_l3 = { DEFINE_QNODE(sm8250_epss_apps_l3, SM8250_MASTER_EPSS_L3_APPS, 32, SM8250_SLAVE_EPSS_L3); DEFINE_QNODE(sm8250_epss_l3, SM8250_SLAVE_EPSS_L3, 32); -static const struct qcom_icc_node *sm8250_epss_l3_nodes[] = { +static const struct qcom_osm_l3_node *sm8250_epss_l3_nodes[] = { [MASTER_EPSS_L3_APPS] = &sm8250_epss_apps_l3, [SLAVE_EPSS_L3_SHARED] = &sm8250_epss_l3, }; -static const struct qcom_icc_desc sm8250_icc_epss_l3 = { +static const struct qcom_osm_l3_desc sm8250_icc_epss_l3 = { .nodes = sm8250_epss_l3_nodes, .num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes), .lut_row_size = EPSS_LUT_ROW_SIZE, @@ -162,11 +162,11 @@ static const struct qcom_icc_desc sm8250_icc_epss_l3 = { .reg_perf_state = EPSS_REG_PERF_STATE, }; -static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) +static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst) { struct qcom_osm_l3_icc_provider *qp; struct icc_provider *provider; - const struct qcom_icc_node *qn; + const struct qcom_osm_l3_node *qn; struct icc_node *n; unsigned int index; u32 agg_peak = 0; @@ -175,7 +175,7 @@ static int qcom_icc_set(struct icc_node *src, struct icc_node *dst) qn = src->data; provider = src->provider; - qp = to_qcom_provider(provider); + qp = to_osm_l3_provider(provider); list_for_each_entry(n, &provider->nodes, node_list) provider->aggregate(n, 0, n->avg_bw, n->peak_bw, @@ -208,10 +208,10 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) u32 info, src, lval, i, prev_freq = 0, freq; static unsigned long hw_rate, xo_rate; struct qcom_osm_l3_icc_provider *qp; - const struct qcom_icc_desc *desc; + const struct qcom_osm_l3_desc *desc; struct icc_onecell_data *data; struct icc_provider *provider; - const struct qcom_icc_node **qnodes; + const struct qcom_osm_l3_node **qnodes; struct icc_node *node; size_t num_nodes; struct clk *clk; @@ -281,7 +281,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) provider = &qp->provider; provider->dev = &pdev->dev; - provider->set = qcom_icc_set; + provider->set = qcom_osm_l3_set; provider->aggregate = icc_std_aggregate; provider->xlate = of_icc_xlate_onecell; INIT_LIST_HEAD(&provider->nodes); @@ -303,7 +303,7 @@ static int qcom_osm_l3_probe(struct platform_device *pdev) } node->name = qnodes[i]->name; - /* Cast away const and add it back in qcom_icc_set() */ + /* Cast away const and add it back in qcom_osm_l3_set() */ node->data = (void *)qnodes[i]; icc_node_add(node, provider); -- cgit v1.2.3 From 9aaf4d2a08182b7ef6d939642a6d92564bd83b2f Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 10 Aug 2021 16:30:35 +0100 Subject: dt-bindings: nintendo-otp: Document the Wii and Wii U OTP support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both of these consoles use the exact same two registers, even at the same address, but the Wii U has eight banks of 128 bytes memory while the Wii only has one, hence the two compatible strings. Reviewed-by: Rob Herring Signed-off-by: Emmanuel Gil Peyrot Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210810153036.1494-2-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/nvmem/nintendo-otp.yaml | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml diff --git a/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml b/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml new file mode 100644 index 000000000000..dbe4ffdd644c --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/nintendo-otp.yaml @@ -0,0 +1,44 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/nvmem/nintendo-otp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Nintendo Wii and Wii U OTP Device Tree Bindings + +description: | + This binding represents the OTP memory as found on a Nintendo Wii or Wii U, + which contains common and per-console keys, signatures and related data + required to access peripherals. + + See https://wiiubrew.org/wiki/Hardware/OTP + +maintainers: + - Emmanuel Gil Peyrot + +allOf: + - $ref: "nvmem.yaml#" + +properties: + compatible: + enum: + - nintendo,hollywood-otp + - nintendo,latte-otp + + reg: + maxItems: 1 + +required: + - compatible + - reg + +unevaluatedProperties: false + +examples: + - | + otp@d8001ec { + compatible = "nintendo,latte-otp"; + reg = <0x0d8001ec 0x8>; + }; + +... -- cgit v1.2.3 From 3683b761fe3a10ad18515acd5368dd601268cfe5 Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Tue, 10 Aug 2021 16:30:36 +0100 Subject: nvmem: nintendo-otp: Add new driver for the Wii and Wii U OTP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This OTP is read-only and contains various keys used by the console to decrypt, encrypt or verify various pieces of storage. Its size depends on the console, it is 128 bytes on the Wii and 1024 bytes on the Wii U (split into eight 128 bytes banks). It can be used directly by writing into one register and reading from the other one, without any additional synchronisation. This driver was written based on reversed documentation, see: https://wiiubrew.org/wiki/Hardware/OTP Tested-by: Jonathan Neuschäfer # on Wii Tested-by: Emmanuel Gil Peyrot # on Wii U Signed-off-by: Emmanuel Gil Peyrot Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210810153036.1494-3-srinivas.kandagatla@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/nvmem/Kconfig | 11 ++++ drivers/nvmem/Makefile | 2 + drivers/nvmem/nintendo-otp.c | 124 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 drivers/nvmem/nintendo-otp.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index dd2019006838..39854d43758b 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -107,6 +107,17 @@ config MTK_EFUSE This driver can also be built as a module. If so, the module will be called efuse-mtk. +config NVMEM_NINTENDO_OTP + tristate "Nintendo Wii and Wii U OTP Support" + help + This is a driver exposing the OTP of a Nintendo Wii or Wii U console. + + This memory contains common and per-console keys, signatures and + related data required to access peripherals. + + This driver can also be built as a module. If so, the module + will be called nvmem-nintendo-otp. + config QCOM_QFPROM tristate "QCOM QFPROM Support" depends on ARCH_QCOM || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index bbea1410240a..dcbbde35b6a8 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -23,6 +23,8 @@ obj-$(CONFIG_NVMEM_LPC18XX_OTP) += nvmem_lpc18xx_otp.o nvmem_lpc18xx_otp-y := lpc18xx_otp.o obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o nvmem-mxs-ocotp-y := mxs-ocotp.o +obj-$(CONFIG_NVMEM_NINTENDO_OTP) += nvmem-nintendo-otp.o +nvmem-nintendo-otp-y := nintendo-otp.o obj-$(CONFIG_MTK_EFUSE) += nvmem_mtk-efuse.o nvmem_mtk-efuse-y := mtk-efuse.o obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o diff --git a/drivers/nvmem/nintendo-otp.c b/drivers/nvmem/nintendo-otp.c new file mode 100644 index 000000000000..33961b17f9f1 --- /dev/null +++ b/drivers/nvmem/nintendo-otp.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Nintendo Wii and Wii U OTP driver + * + * This is a driver exposing the OTP of a Nintendo Wii or Wii U console. + * + * This memory contains common and per-console keys, signatures and + * related data required to access peripherals. + * + * Based on reversed documentation from https://wiiubrew.org/wiki/Hardware/OTP + * + * Copyright (C) 2021 Emmanuel Gil Peyrot + */ + +#include +#include +#include +#include +#include +#include +#include + +#define HW_OTPCMD 0 +#define HW_OTPDATA 4 +#define OTP_READ 0x80000000 +#define BANK_SIZE 128 +#define WORD_SIZE 4 + +struct nintendo_otp_priv { + void __iomem *regs; +}; + +struct nintendo_otp_devtype_data { + const char *name; + unsigned int num_banks; +}; + +static const struct nintendo_otp_devtype_data hollywood_otp_data = { + .name = "wii-otp", + .num_banks = 1, +}; + +static const struct nintendo_otp_devtype_data latte_otp_data = { + .name = "wiiu-otp", + .num_banks = 8, +}; + +static int nintendo_otp_reg_read(void *context, + unsigned int reg, void *_val, size_t bytes) +{ + struct nintendo_otp_priv *priv = context; + u32 *val = _val; + int words = bytes / WORD_SIZE; + u32 bank, addr; + + while (words--) { + bank = (reg / BANK_SIZE) << 8; + addr = (reg / WORD_SIZE) % (BANK_SIZE / WORD_SIZE); + iowrite32be(OTP_READ | bank | addr, priv->regs + HW_OTPCMD); + *val++ = ioread32be(priv->regs + HW_OTPDATA); + reg += WORD_SIZE; + } + + return 0; +} + +static const struct of_device_id nintendo_otp_of_table[] = { + { .compatible = "nintendo,hollywood-otp", .data = &hollywood_otp_data }, + { .compatible = "nintendo,latte-otp", .data = &latte_otp_data }, + {/* sentinel */}, +}; +MODULE_DEVICE_TABLE(of, nintendo_otp_of_table); + +static int nintendo_otp_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id = + of_match_device(nintendo_otp_of_table, dev); + struct resource *res; + struct nvmem_device *nvmem; + struct nintendo_otp_priv *priv; + + struct nvmem_config config = { + .stride = WORD_SIZE, + .word_size = WORD_SIZE, + .reg_read = nintendo_otp_reg_read, + .read_only = true, + .root_only = true, + }; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + if (of_id->data) { + const struct nintendo_otp_devtype_data *data = of_id->data; + config.name = data->name; + config.size = data->num_banks * BANK_SIZE; + } + + config.dev = dev; + config.priv = priv; + + nvmem = devm_nvmem_register(dev, &config); + + return PTR_ERR_OR_ZERO(nvmem); +} + +static struct platform_driver nintendo_otp_driver = { + .probe = nintendo_otp_probe, + .driver = { + .name = "nintendo-otp", + .of_match_table = nintendo_otp_of_table, + }, +}; +module_platform_driver(nintendo_otp_driver); +MODULE_AUTHOR("Emmanuel Gil Peyrot "); +MODULE_DESCRIPTION("Nintendo Wii and Wii U OTP driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 16af5357d5842785a5646684281fad259310dce0 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 15 Aug 2021 22:42:06 +0100 Subject: misc: gehc-achc: Fix spelling mistake "Verfication" -> "Verification" There is a spelling mistake in a dev_dbg debug message. Fix it. Reviewed-by: Sebastian Reichel Signed-off-by: Colin Ian King Link: https://lore.kernel.org/r/20210815214206.47970-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/gehc-achc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/gehc-achc.c b/drivers/misc/gehc-achc.c index 891d9a214454..02f33bc60c56 100644 --- a/drivers/misc/gehc-achc.c +++ b/drivers/misc/gehc-achc.c @@ -280,7 +280,7 @@ static int ezport_flash_compare(struct spi_device *spi, u32 address, ret = memcmp(payload, buffer + 4 + 1, payload_size); if (ret) { ret = -EBADMSG; - dev_dbg(&spi->dev, "Verfication failure @ %06x", address); + dev_dbg(&spi->dev, "Verification failure @ %06x", address); print_hex_dump_bytes("fw: ", DUMP_PREFIX_OFFSET, payload, payload_size); print_hex_dump_bytes("dev: ", DUMP_PREFIX_OFFSET, buffer + 4, payload_size); } -- cgit v1.2.3 From 9e1b28b773881963150a7e3a11d4d00b9df0129a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 15 Aug 2021 17:05:31 -0700 Subject: char: move RANDOM_TRUST_CPU & RANDOM_TRUST_BOOTLOADER into the Character devices menu Include RANDOM_TRUST_CPU and RANDOM_TRUST_BOOTLOADER inside the "Character devices" menu so that they are listed (presented) with other Character devices. Cc: Arnd Bergmann Cc: Greg Kroah-Hartman Cc: Hsin-Yi Wang Cc: Theodore Ts'o Signed-off-by: Randy Dunlap Link: https://lore.kernel.org/r/20210816000531.17934-1-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ea3ead00f30f..740811893c57 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -427,8 +427,6 @@ config ADI and SSM (Silicon Secured Memory). Intended consumers of this driver include crash and makedumpfile. -endmenu - config RANDOM_TRUST_CPU bool "Trust the CPU manufacturer to initialize Linux's CRNG" depends on ARCH_RANDOM @@ -452,3 +450,5 @@ config RANDOM_TRUST_BOOTLOADER booloader is trustworthy so it will be added to the kernel's entropy pool. Otherwise, say N here so it will be regarded as device input that only mixes the entropy pool. + +endmenu -- cgit v1.2.3 From e956d4fceba3aeb1cc088d043048b1d2157427b0 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:46 +0200 Subject: phy: cadence-torrent: Remove use of CamelCase to fix checkpatch CHECK message Script checkpatch with --strict option gives message: CHECK: Avoid CamelCase: CHECK: Avoid CamelCase: Fix this by removing CamelCase usage. No functional change. Signed-off-by: Swapnil Jakhade Reviewed-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210728145454.15945-2-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 0477e7beebbf..ff647669f1a3 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -24,8 +24,8 @@ #include #include -#define REF_CLK_19_2MHz 19200000 -#define REF_CLK_25MHz 25000000 +#define REF_CLK_19_2MHZ 19200000 +#define REF_CLK_25MHZ 25000000 #define MAX_NUM_LANES 4 #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ @@ -695,12 +695,12 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, ndelay(200); /* DP Rate Change - VCO Output settings. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) { + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { /* PMA common configuration 19.2MHz */ cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, dp->ssc); cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) { + } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { /* PMA common configuration 25MHz */ cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, dp->ssc); @@ -993,8 +993,8 @@ static int cdns_torrent_dp_init(struct phy *phy) struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; switch (cdns_phy->ref_clk_rate) { - case REF_CLK_19_2MHz: - case REF_CLK_25MHz: + case REF_CLK_19_2MHZ: + case REF_CLK_25MHZ: /* Valid Ref Clock Rate */ break; default: @@ -1026,11 +1026,11 @@ static int cdns_torrent_dp_init(struct phy *phy) /* PHY PMA registers configuration functions */ /* Initialize PHY with max supported link rate, without SSC. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, cdns_phy->max_bit_rate, false); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, cdns_phy->max_bit_rate, false); @@ -1074,10 +1074,10 @@ static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, { unsigned int i; - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) /* PMA common configuration 19.2MHz */ cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) /* PMA common configuration 25MHz */ cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); @@ -1529,10 +1529,10 @@ static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, unsigned int lane) { /* Per lane, refclock-dependent receiver detection setting */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHz) + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], TX_RCVDET_ST_TMR, 0x0780); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHz) + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], TX_RCVDET_ST_TMR, 0x09C4); -- cgit v1.2.3 From 5b16a790f18d234187f31eab0a222bd53cb12b9e Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:47 +0200 Subject: phy: cadence-torrent: Reorder few functions to remove function declarations Reorder some functions to avoid function declarations. No functional change. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-3-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 1937 ++++++++++++++--------------- 1 file changed, 953 insertions(+), 984 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index ff647669f1a3..4b2d6d3eace9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -333,57 +333,6 @@ struct cdns_torrent_derived_refclk { #define to_cdns_torrent_derived_refclk(_hw) \ container_of(_hw, struct cdns_torrent_derived_refclk, hw) -static int cdns_torrent_phy_init(struct phy *phy); -static int cdns_torrent_dp_init(struct phy *phy); -static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes); -static -int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy); -static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, - struct cdns_torrent_inst *inst); -static -void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy); -static -void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc); -static -void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy); -static -void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc); -static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, - unsigned int lane); -static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, - u32 rate, u32 num_lanes); -static int cdns_torrent_dp_configure(struct phy *phy, - union phy_configure_opts *opts); -static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes, - enum phy_powerstate powerstate); -static int cdns_torrent_phy_on(struct phy *phy); -static int cdns_torrent_phy_off(struct phy *phy); - -static const struct phy_ops cdns_torrent_phy_ops = { - .init = cdns_torrent_phy_init, - .configure = cdns_torrent_dp_configure, - .power_on = cdns_torrent_phy_on, - .power_off = cdns_torrent_phy_off, - .owner = THIS_MODULE, -}; - -static int cdns_torrent_noop_phy_on(struct phy *phy) -{ - /* Give 5ms to 10ms delay for the PIPE clock to be stable */ - usleep_range(5000, 10000); - - return 0; -} - -static const struct phy_ops noop_ops = { - .power_on = cdns_torrent_noop_phy_on, - .owner = THIS_MODULE, -}; - struct cdns_reg_pairs { u32 val; u32 off; @@ -615,444 +564,607 @@ static const struct coefficients vltg_coeff[4][4] = { } }; -/* - * Enable or disable PLL for selected lanes. - */ -static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp, - bool enable) +static +void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy) { - u32 rd_val; - u32 ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - - /* - * Used to determine, which bits to check for or enable in - * PHY_PMA_XCVR_PLLCLK_EN register. - */ - u32 pll_bits; - /* Used to enable or disable lanes. */ - u32 pll_val; - - /* Select values of registers and mask, depending on enabled lane - * count. - */ - switch (dp->lanes) { - /* lane 0 */ - case (1): - pll_bits = 0x00000001; - break; - /* lanes 0-1 */ - case (2): - pll_bits = 0x00000003; - break; - /* lanes 0-3, all */ - default: - pll_bits = 0x0000000F; - break; - } - - if (enable) - pll_val = pll_bits; - else - pll_val = 0x00000000; + struct regmap *regmap = cdns_phy->regmap_common_cdb; - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val); + /* refclock registers - assumes 19.2 MHz refclock */ + cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0014); + cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0027); + cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00A1); + cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0027); + cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00A1); + cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x0060); + cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x0060); + cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0014); + cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x0018); + cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0005); + cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x0018); + cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0005); + cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x0240); + cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0005); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000B); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x0137); - /* Wait for acknowledgment from PHY. */ - ret = regmap_read_poll_timeout(regmap, - PHY_PMA_XCVR_PLLCLK_EN_ACK, - rd_val, - (rd_val & pll_bits) == pll_val, - 0, POLL_TIMEOUT_US); - ndelay(100); - return ret; + /* PLL registers */ + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00C0); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00C0); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0260); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0260); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); } /* - * Perform register operations related to setting link rate, once powerstate is - * set and PLL disable request was processed. + * Set registers responsible for enabling and configuring SSC, with second and + * third register values provided by parameters. */ -static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) +static +void cdns_torrent_dp_enable_ssc_19_2mhz(struct cdns_torrent_phy *cdns_phy, + u32 ctrl2_val, u32 ctrl3_val) { - u32 ret; - u32 read_val; - - /* Disable the cmn_pll0_en before re-programming the new data rate. */ - regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); - - /* - * Wait for PLL ready de-assertion. - * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, - read_val, - ((read_val >> 2) & 0x01) != 0, - 0, POLL_TIMEOUT_US); - if (ret) - return ret; - ndelay(200); - - /* DP Rate Change - VCO Output settings. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { - /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { - /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - } - cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); - - /* Enable the cmn_pll0_en. */ - regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3); + struct regmap *regmap = cdns_phy->regmap_common_cdb; - /* - * Wait for PLL ready assertion. - * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, - read_val, - (read_val & 0x01) != 0, - 0, POLL_TIMEOUT_US); - return ret; + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl3_val); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl3_val); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003); } -/* - * Verify, that parameters to configure PHY with are correct. - */ -static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst, - struct phy_configure_opts_dp *dp) +static +void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, + u32 rate, bool ssc) { - u8 i; - - /* If changing link rate was required, verify it's supported. */ - if (dp->set_rate) { - switch (dp->link_rate) { - case 1620: - case 2160: - case 2430: - case 2700: - case 3240: - case 4320: - case 5400: - case 8100: - /* valid bit rate */ - break; - default: - return -EINVAL; - } - } + struct regmap *regmap = cdns_phy->regmap_common_cdb; - /* Verify lane count. */ - switch (dp->lanes) { - case 1: - case 2: - case 4: - /* valid lane count. */ + /* Assumes 19.2 MHz refclock */ + switch (rate) { + /* Setting VCO for 10.8GHz */ + case 2700: + case 5400: + cdns_torrent_phy_write(regmap, + CMN_PLL0_INTDIV_M0, 0x0119); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL0_HIGH_THR_M0, 0x00BC); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL0_CTRL_M0, 0x0012); + cdns_torrent_phy_write(regmap, + CMN_PLL1_INTDIV_M0, 0x0119); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_HIGH_THR_M0, 0x00BC); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL1_CTRL_M0, 0x0012); + if (ssc) + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A, + 0x006A); break; - default: - return -EINVAL; - } - - /* Check against actual number of PHY's lanes. */ - if (dp->lanes > inst->num_lanes) - return -EINVAL; - - /* - * If changing voltages is required, check swing and pre-emphasis - * levels, per-lane. - */ - if (dp->set_voltages) { - /* Lane count verified previously. */ - for (i = 0; i < dp->lanes; i++) { - if (dp->voltage[i] > 3 || dp->pre[i] > 3) - return -EINVAL; + /* Setting VCO for 9.72GHz */ + case 1620: + case 2430: + case 3240: + cdns_torrent_phy_write(regmap, + CMN_PLL0_INTDIV_M0, 0x01FA); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL0_HIGH_THR_M0, 0x0152); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_INTDIV_M0, 0x01FA); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_HIGH_THR_M0, 0x0152); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + if (ssc) + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD, + 0x0069); + break; + /* Setting VCO for 8.64GHz */ + case 2160: + case 4320: + cdns_torrent_phy_write(regmap, + CMN_PLL0_INTDIV_M0, 0x01C2); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL0_HIGH_THR_M0, 0x012C); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_INTDIV_M0, 0x01C2); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_HIGH_THR_M0, 0x012C); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + if (ssc) + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536, + 0x0069); + break; + /* Setting VCO for 8.1GHz */ + case 8100: + cdns_torrent_phy_write(regmap, + CMN_PLL0_INTDIV_M0, 0x01A5); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVL_M0, 0xE000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL0_HIGH_THR_M0, 0x011A); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_INTDIV_M0, 0x01A5); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVL_M0, 0xE000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_HIGH_THR_M0, 0x011A); + cdns_torrent_phy_write(regmap, + CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + if (ssc) + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7, + 0x006A); + break; + } - /* Sum of voltage swing and pre-emphasis levels cannot - * exceed 3. - */ - if (dp->voltage[i] + dp->pre[i] > 3) - return -EINVAL; - } + if (ssc) { + cdns_torrent_phy_write(regmap, + CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E); + cdns_torrent_phy_write(regmap, + CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); + cdns_torrent_phy_write(regmap, + CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E); + cdns_torrent_phy_write(regmap, + CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); + } else { + cdns_torrent_phy_write(regmap, + CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260); + cdns_torrent_phy_write(regmap, + CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260); + /* Set reset register values to disable SSC */ + cdns_torrent_phy_write(regmap, + CMN_PLL0_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL0_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); + cdns_torrent_phy_write(regmap, + CMN_PLL1_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, + CMN_PLL1_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); } - return 0; + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099); + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x0099); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x0099); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099); } -/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */ -static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes) +static +void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy) { - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - u32 pwr_state = cdns_torrent_dp_read(regmap, - PHY_PMA_XCVR_POWER_STATE_REQ); - u32 pll_clk_en = cdns_torrent_dp_read(regmap, - PHY_PMA_XCVR_PLLCLK_EN); - - /* Lane 0 is always enabled. */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_0); - pll_clk_en &= ~0x01U; - - if (num_lanes > 1) { - /* lane 1 */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_1); - pll_clk_en &= ~(0x01U << 1); - } + struct regmap *regmap = cdns_phy->regmap_common_cdb; - if (num_lanes > 2) { - /* lanes 2 and 3 */ - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_2); - pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << - PHY_POWER_STATE_LN_3); - pll_clk_en &= ~(0x01U << 2); - pll_clk_en &= ~(0x01U << 3); - } + /* refclock registers - assumes 25 MHz refclock */ + cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0019); + cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0032); + cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00D1); + cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0032); + cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00D1); + cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x007D); + cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x007D); + cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0019); + cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x001E); + cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0006); + cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x001E); + cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0006); + cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x02EE); + cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0006); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000E); + cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x012B); - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state); - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en); + /* PLL registers */ + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00FA); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00FA); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0317); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0317); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); } -/* Configure lane count as required. */ -static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) +/* + * Set registers responsible for enabling and configuring SSC, with second + * register value provided by a parameter. + */ +static void cdns_torrent_dp_enable_ssc_25mhz(struct cdns_torrent_phy *cdns_phy, + u32 ctrl2_val) { - u32 value; - u32 ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - u8 lane_mask = (1 << dp->lanes) - 1; - - value = cdns_torrent_dp_read(regmap, PHY_RESET); - /* clear pma_tx_elec_idle_ln_* bits. */ - value &= ~PMA_TX_ELEC_IDLE_MASK; - /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */ - value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) & - PMA_TX_ELEC_IDLE_MASK; - cdns_torrent_dp_write(regmap, PHY_RESET, value); - - /* reset the link by asserting phy_l00_reset_n low */ - cdns_torrent_dp_write(regmap, PHY_RESET, - value & (~PHY_L00_RESET_N_MASK)); - - /* - * Assert lane reset on unused lanes and lane 0 so they remain in reset - * and powered down when re-enabling the link - */ - value = (value & 0x0000FFF0) | (0x0000000E & lane_mask); - cdns_torrent_dp_write(regmap, PHY_RESET, value); + struct regmap *regmap = cdns_phy->regmap_common_cdb; - cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x007F); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x007F); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003); +} - /* release phy_l0*_reset_n based on used laneCount */ - value = (value & 0x0000FFF0) | (0x0000000F & lane_mask); - cdns_torrent_dp_write(regmap, PHY_RESET, value); +static +void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, + u32 rate, bool ssc) +{ + struct regmap *regmap = cdns_phy->regmap_common_cdb; - /* Wait, until PHY gets ready after releasing PHY reset signal. */ - ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); - if (ret) - return ret; - - ndelay(100); + /* Assumes 25 MHz refclock */ + switch (rate) { + /* Setting VCO for 10.8GHz */ + case 2700: + case 5400: + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01B0); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0120); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01B0); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0120); + if (ssc) + cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x0423); + break; + /* Setting VCO for 9.72GHz */ + case 1620: + case 2430: + case 3240: + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0184); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xCCCD); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0104); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0184); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xCCCD); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0104); + if (ssc) + cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x03B9); + break; + /* Setting VCO for 8.64GHz */ + case 2160: + case 4320: + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0159); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x999A); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00E7); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0159); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x999A); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00E7); + if (ssc) + cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x034F); + break; + /* Setting VCO for 8.1GHz */ + case 8100: + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0144); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00D8); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0144); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00D8); + if (ssc) + cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x031A); + break; + } - /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); - ret = cdns_torrent_dp_run(cdns_phy, dp->lanes); + if (ssc) { + cdns_torrent_phy_write(regmap, + CMN_PLL0_VCOCAL_PLLCNT_START, 0x0315); + cdns_torrent_phy_write(regmap, + CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); + cdns_torrent_phy_write(regmap, + CMN_PLL1_VCOCAL_PLLCNT_START, 0x0315); + cdns_torrent_phy_write(regmap, + CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); + } else { + cdns_torrent_phy_write(regmap, + CMN_PLL0_VCOCAL_PLLCNT_START, 0x0317); + cdns_torrent_phy_write(regmap, + CMN_PLL1_VCOCAL_PLLCNT_START, 0x0317); + /* Set reset register values to disable SSC */ + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, + CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); + } - return ret; + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x00C7); + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x00C7); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x00C7); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7); } -/* Configure link rate as required. */ -static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) +static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, + unsigned int lane) { - u32 ret; + /* Per lane, refclock-dependent receiver detection setting */ + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_RCVDET_ST_TMR, 0x0780); + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_RCVDET_ST_TMR, 0x09C4); - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A3); - if (ret) - return ret; - ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false); - if (ret) - return ret; - ndelay(200); + /* Writing Tx/Rx Power State Controllers registers */ + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_PSC_A0, 0x00FB); + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_PSC_A2, 0x04AA); + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_PSC_A3, 0x04AA); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_PSC_A0, 0x0000); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_PSC_A2, 0x0000); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_PSC_A3, 0x0000); - ret = cdns_torrent_dp_configure_rate(cdns_phy, dp); - if (ret) - return ret; - ndelay(200); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_PSC_CAL, 0x0000); - ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true); - if (ret) - return ret; - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A2); - if (ret) - return ret; - ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, - POWERSTATE_A0); - if (ret) - return ret; - ndelay(900); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_REE_GCSM1_CTRL, 0x0000); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_REE_GCSM2_CTRL, 0x0000); + cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], + RX_REE_PERGCSM_CTRL, 0x0000); - return ret; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + XCVR_DIAG_BIDI_CTRL, 0x000F); + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + XCVR_DIAG_PLLDRC_CTRL, 0x0001); + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + XCVR_DIAG_HSCLK_SEL, 0x0000); } -/* Configure voltage swing and pre-emphasis for all enabled lanes. */ -static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy, - struct phy_configure_opts_dp *dp) +static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, + struct cdns_torrent_inst *inst) { - u8 lane; - u16 val; - - for (lane = 0; lane < dp->lanes; lane++) { - val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA); - /* - * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the - * current state of the analog TX driver. - */ - val |= TX_DIAG_ACYA_HBDC_MASK; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA, val); + unsigned int i; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_CTRL, 0x08A4); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - DRV_DIAG_TX_DRV, val); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_MGNFS_MULT_000, - val); - val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_TXCC_CPOST_MULT_00, - val); + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + /* PMA common configuration 19.2MHz */ + cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + /* PMA common configuration 25MHz */ + cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA); - /* - * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of - * analog TX driver to reflect the new programmed one. - */ - val &= ~TX_DIAG_ACYA_HBDC_MASK; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_DIAG_ACYA, val); - } -}; + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < inst->num_lanes; i++) + cdns_torrent_dp_pma_lane_cfg(cdns_phy, i); +} -static int cdns_torrent_dp_configure(struct phy *phy, - union phy_configure_opts *opts) +/* + * Enable or disable PLL for selected lanes. + */ +static int cdns_torrent_dp_set_pll_en(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp, + bool enable) { - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - int ret; - - ret = cdns_torrent_dp_verify_config(inst, &opts->dp); - if (ret) { - dev_err(&phy->dev, "invalid params for phy configure\n"); - return ret; - } + u32 rd_val; + u32 ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - if (opts->dp.set_lanes) { - ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp); - if (ret) { - dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n"); - return ret; - } - } + /* + * Used to determine, which bits to check for or enable in + * PHY_PMA_XCVR_PLLCLK_EN register. + */ + u32 pll_bits; + /* Used to enable or disable lanes. */ + u32 pll_val; - if (opts->dp.set_rate) { - ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp); - if (ret) { - dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n"); - return ret; - } + /* Select values of registers and mask, depending on enabled lane + * count. + */ + switch (dp->lanes) { + /* lane 0 */ + case (1): + pll_bits = 0x00000001; + break; + /* lanes 0-1 */ + case (2): + pll_bits = 0x00000003; + break; + /* lanes 0-3, all */ + default: + pll_bits = 0x0000000F; + break; } - if (opts->dp.set_voltages) - cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp); + if (enable) + pll_val = pll_bits; + else + pll_val = 0x00000000; + + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_val); + /* Wait for acknowledgment from PHY. */ + ret = regmap_read_poll_timeout(regmap, + PHY_PMA_XCVR_PLLCLK_EN_ACK, + rd_val, + (rd_val & pll_bits) == pll_val, + 0, POLL_TIMEOUT_US); + ndelay(100); return ret; } -static int cdns_torrent_dp_init(struct phy *phy) +static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, + u32 num_lanes, + enum phy_powerstate powerstate) { - unsigned char lane_bits; - int ret; - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + /* Register value for power state for a single byte. */ + u32 value_part; + u32 value; + u32 mask; + u32 read_val; + u32 ret; struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - switch (cdns_phy->ref_clk_rate) { - case REF_CLK_19_2MHZ: - case REF_CLK_25MHZ: - /* Valid Ref Clock Rate */ + switch (powerstate) { + case (POWERSTATE_A0): + value_part = 0x01U; + break; + case (POWERSTATE_A2): + value_part = 0x04U; break; default: - dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); - return -EINVAL; + /* Powerstate A3 */ + value_part = 0x08U; + break; } - cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ - - /* PHY PMA registers configuration function */ - cdns_torrent_dp_pma_cfg(cdns_phy, inst); - - /* - * Set lines power state to A0 - * Set lines pll clk enable to 0 + /* Select values of registers and mask, depending on enabled + * lane count. */ - cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes); + switch (num_lanes) { + /* lane 0 */ + case (1): + value = value_part; + mask = 0x0000003FU; + break; + /* lanes 0-1 */ + case (2): + value = (value_part + | (value_part << 8)); + mask = 0x00003F3FU; + break; + /* lanes 0-3, all */ + default: + value = (value_part + | (value_part << 8) + | (value_part << 16) + | (value_part << 24)); + mask = 0x3F3F3F3FU; + break; + } - /* - * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on - * used lanes - */ - lane_bits = (1 << inst->num_lanes) - 1; - cdns_torrent_dp_write(regmap, PHY_RESET, - ((0xF & ~lane_bits) << 4) | (0xF & lane_bits)); + /* Set power state A. */ + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, value); + /* Wait, until PHY acknowledges power state completion. */ + ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK, + read_val, (read_val & mask) == value, 0, + POLL_TIMEOUT_US); + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000); + ndelay(100); - /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); + return ret; +} - /* PHY PMA registers configuration functions */ - /* Initialize PHY with max supported link rate, without SSC. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) - cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, - cdns_phy->max_bit_rate, - false); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) - cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, - cdns_phy->max_bit_rate, - false); - cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, - inst->num_lanes); +static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) +{ + unsigned int read_val; + int ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - /* take out of reset */ - regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1); + /* + * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the + * master lane + */ + ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_PLLCLK_EN_ACK, + read_val, read_val & 1, + 0, POLL_TIMEOUT_US); + if (ret == -ETIMEDOUT) { + dev_err(cdns_phy->dev, + "timeout waiting for link PLL clock enable ack\n"); + return ret; + } - cdns_torrent_phy_on(phy); + ndelay(100); - ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); + ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, + POWERSTATE_A2); if (ret) return ret; - ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes); + ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, + POWERSTATE_A0); return ret; } -static -int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) +static int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) { unsigned int reg; int ret; @@ -1069,595 +1181,481 @@ int cdns_torrent_dp_wait_pma_cmn_ready(struct cdns_torrent_phy *cdns_phy) return 0; } -static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, - struct cdns_torrent_inst *inst) +static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, + u32 rate, u32 num_lanes) { + unsigned int clk_sel_val = 0; + unsigned int hsclk_div_val = 0; unsigned int i; - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) - /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) - /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - - /* PMA lane configuration to deal with multi-link operation */ - for (i = 0; i < inst->num_lanes; i++) - cdns_torrent_dp_pma_lane_cfg(cdns_phy, i); -} + /* 16'h0000 for single DP link configuration */ + regmap_field_write(cdns_phy->phy_pll_cfg, 0x0); -static -void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy) -{ - struct regmap *regmap = cdns_phy->regmap_common_cdb; + switch (rate) { + case 1620: + clk_sel_val = 0x0f01; + hsclk_div_val = 2; + break; + case 2160: + case 2430: + case 2700: + clk_sel_val = 0x0701; + hsclk_div_val = 1; + break; + case 3240: + clk_sel_val = 0x0b00; + hsclk_div_val = 2; + break; + case 4320: + case 5400: + clk_sel_val = 0x0301; + hsclk_div_val = 0; + break; + case 8100: + clk_sel_val = 0x0200; + hsclk_div_val = 0; + break; + } - /* refclock registers - assumes 19.2 MHz refclock */ - cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0014); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0027); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00A1); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0027); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00A1); - cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x0060); - cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x0060); - cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0014); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x0018); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x0018); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x0240); - cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000B); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x0137); + cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, + CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val); + cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, + CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val); - /* PLL registers */ - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00C0); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00C0); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0260); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0260); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); + /* PMA lane configuration to deal with multi-link operation */ + for (i = 0; i < num_lanes; i++) + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i], + XCVR_DIAG_HSCLK_DIV, hsclk_div_val); } /* - * Set registers responsible for enabling and configuring SSC, with second and - * third register values provided by parameters. + * Perform register operations related to setting link rate, once powerstate is + * set and PLL disable request was processed. */ -static -void cdns_torrent_dp_enable_ssc_19_2mhz(struct cdns_torrent_phy *cdns_phy, - u32 ctrl2_val, u32 ctrl3_val) -{ - struct regmap *regmap = cdns_phy->regmap_common_cdb; +static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 ret; + u32 read_val; - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl3_val); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl3_val); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003); + /* Disable the cmn_pll0_en before re-programming the new data rate. */ + regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); + + /* + * Wait for PLL ready de-assertion. + * For PLL0 - PHY_PMA_CMN_CTRL2[2] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, + read_val, + ((read_val >> 2) & 0x01) != 0, + 0, POLL_TIMEOUT_US); + if (ret) + return ret; + ndelay(200); + + /* DP Rate Change - VCO Output settings. */ + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { + /* PMA common configuration 19.2MHz */ + cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, + dp->ssc); + cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); + } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { + /* PMA common configuration 25MHz */ + cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, + dp->ssc); + cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); + } + cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); + + /* Enable the cmn_pll0_en. */ + regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x3); + + /* + * Wait for PLL ready assertion. + * For PLL0 - PHY_PMA_CMN_CTRL2[0] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_2, + read_val, + (read_val & 0x01) != 0, + 0, POLL_TIMEOUT_US); + return ret; } -static -void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc) +/* + * Verify, that parameters to configure PHY with are correct. + */ +static int cdns_torrent_dp_verify_config(struct cdns_torrent_inst *inst, + struct phy_configure_opts_dp *dp) { - struct regmap *regmap = cdns_phy->regmap_common_cdb; + u8 i; - /* Assumes 19.2 MHz refclock */ - switch (rate) { - /* Setting VCO for 10.8GHz */ - case 2700: - case 5400: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x0119); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x00BC); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0012); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x0119); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x00BC); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0012); - if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A, - 0x006A); - break; - /* Setting VCO for 9.72GHz */ - case 1620: - case 2430: - case 3240: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01FA); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x0152); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01FA); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x0152); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); - if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD, - 0x0069); - break; - /* Setting VCO for 8.64GHz */ - case 2160: - case 4320: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01C2); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x012C); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01C2); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x012C); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); - if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536, - 0x0069); - break; - /* Setting VCO for 8.1GHz */ - case 8100: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01A5); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0xE000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x011A); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01A5); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0xE000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x011A); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); - if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7, - 0x006A); + /* If changing link rate was required, verify it's supported. */ + if (dp->set_rate) { + switch (dp->link_rate) { + case 1620: + case 2160: + case 2430: + case 2700: + case 3240: + case 4320: + case 5400: + case 8100: + /* valid bit rate */ + break; + default: + return -EINVAL; + } + } + + /* Verify lane count. */ + switch (dp->lanes) { + case 1: + case 2: + case 4: + /* valid lane count. */ break; + default: + return -EINVAL; } - if (ssc) { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); - } else { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260); - /* Set reset register values to disable SSC */ - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); + /* Check against actual number of PHY's lanes. */ + if (dp->lanes > inst->num_lanes) + return -EINVAL; + + /* + * If changing voltages is required, check swing and pre-emphasis + * levels, per-lane. + */ + if (dp->set_voltages) { + /* Lane count verified previously. */ + for (i = 0; i < dp->lanes; i++) { + if (dp->voltage[i] > 3 || dp->pre[i] > 3) + return -EINVAL; + + /* Sum of voltage swing and pre-emphasis levels cannot + * exceed 3. + */ + if (dp->voltage[i] + dp->pre[i] > 3) + return -EINVAL; + } } - cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099); - cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x0099); - cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x0099); - cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099); + return 0; } -static -void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy) +/* Set power state A0 and PLL clock enable to 0 on enabled lanes. */ +static void cdns_torrent_dp_set_a0_pll(struct cdns_torrent_phy *cdns_phy, + u32 num_lanes) { - struct regmap *regmap = cdns_phy->regmap_common_cdb; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + u32 pwr_state = cdns_torrent_dp_read(regmap, + PHY_PMA_XCVR_POWER_STATE_REQ); + u32 pll_clk_en = cdns_torrent_dp_read(regmap, + PHY_PMA_XCVR_PLLCLK_EN); - /* refclock registers - assumes 25 MHz refclock */ - cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0019); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0032); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00D1); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0032); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00D1); - cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x007D); - cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x007D); - cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0019); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x001E); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x001E); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x02EE); - cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000E); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x012B); + /* Lane 0 is always enabled. */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_0); + pll_clk_en &= ~0x01U; + + if (num_lanes > 1) { + /* lane 1 */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_1); + pll_clk_en &= ~(0x01U << 1); + } + + if (num_lanes > 2) { + /* lanes 2 and 3 */ + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_2); + pwr_state &= ~(PMA_XCVR_POWER_STATE_REQ_LN_MASK << + PHY_POWER_STATE_LN_3); + pll_clk_en &= ~(0x01U << 2); + pll_clk_en &= ~(0x01U << 3); + } + + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, pwr_state); + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, pll_clk_en); +} + +/* Configure lane count as required. */ +static int cdns_torrent_dp_set_lanes(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 value; + u32 ret; + struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + u8 lane_mask = (1 << dp->lanes) - 1; + + value = cdns_torrent_dp_read(regmap, PHY_RESET); + /* clear pma_tx_elec_idle_ln_* bits. */ + value &= ~PMA_TX_ELEC_IDLE_MASK; + /* Assert pma_tx_elec_idle_ln_* for disabled lanes. */ + value |= ((~lane_mask) << PMA_TX_ELEC_IDLE_SHIFT) & + PMA_TX_ELEC_IDLE_MASK; + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + /* reset the link by asserting phy_l00_reset_n low */ + cdns_torrent_dp_write(regmap, PHY_RESET, + value & (~PHY_L00_RESET_N_MASK)); + + /* + * Assert lane reset on unused lanes and lane 0 so they remain in reset + * and powered down when re-enabling the link + */ + value = (value & 0x0000FFF0) | (0x0000000E & lane_mask); + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + cdns_torrent_dp_set_a0_pll(cdns_phy, dp->lanes); + + /* release phy_l0*_reset_n based on used laneCount */ + value = (value & 0x0000FFF0) | (0x0000000F & lane_mask); + cdns_torrent_dp_write(regmap, PHY_RESET, value); + + /* Wait, until PHY gets ready after releasing PHY reset signal. */ + ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); + if (ret) + return ret; + + ndelay(100); + + /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); + + ret = cdns_torrent_dp_run(cdns_phy, dp->lanes); + + return ret; +} + +/* Configure link rate as required. */ +static int cdns_torrent_dp_set_rate(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) +{ + u32 ret; + + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A3); + if (ret) + return ret; + ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, false); + if (ret) + return ret; + ndelay(200); + + ret = cdns_torrent_dp_configure_rate(cdns_phy, dp); + if (ret) + return ret; + ndelay(200); - /* PLL registers */ - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00FA); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00FA); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0317); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0317); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); + ret = cdns_torrent_dp_set_pll_en(cdns_phy, dp, true); + if (ret) + return ret; + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A2); + if (ret) + return ret; + ret = cdns_torrent_dp_set_power_state(cdns_phy, dp->lanes, + POWERSTATE_A0); + if (ret) + return ret; + ndelay(900); + + return ret; } -/* - * Set registers responsible for enabling and configuring SSC, with second - * register value provided by a parameter. - */ -static void cdns_torrent_dp_enable_ssc_25mhz(struct cdns_torrent_phy *cdns_phy, - u32 ctrl2_val) +/* Configure voltage swing and pre-emphasis for all enabled lanes. */ +static void cdns_torrent_dp_set_voltages(struct cdns_torrent_phy *cdns_phy, + struct phy_configure_opts_dp *dp) { - struct regmap *regmap = cdns_phy->regmap_common_cdb; + u8 lane; + u16 val; - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0001); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, ctrl2_val); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x007F); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0001); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, ctrl2_val); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x007F); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0003); -} + for (lane = 0; lane < dp->lanes; lane++) { + val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA); + /* + * Write 1 to register bit TX_DIAG_ACYA[0] to freeze the + * current state of the analog TX driver. + */ + val |= TX_DIAG_ACYA_HBDC_MASK; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA, val); -static -void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, - u32 rate, bool ssc) + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_CTRL, 0x08A4); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].diag_tx_drv; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + DRV_DIAG_TX_DRV, val); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].mgnfs_mult; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_MGNFS_MULT_000, + val); + val = vltg_coeff[dp->voltage[lane]][dp->pre[lane]].cpost_mult; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_TXCC_CPOST_MULT_00, + val); + + val = cdns_torrent_phy_read(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA); + /* + * Write 0 to register bit TX_DIAG_ACYA[0] to allow the state of + * analog TX driver to reflect the new programmed one. + */ + val &= ~TX_DIAG_ACYA_HBDC_MASK; + cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], + TX_DIAG_ACYA, val); + } +}; + +static int cdns_torrent_dp_configure(struct phy *phy, + union phy_configure_opts *opts) { - struct regmap *regmap = cdns_phy->regmap_common_cdb; + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + int ret; - /* Assumes 25 MHz refclock */ - switch (rate) { - /* Setting VCO for 10.8GHz */ - case 2700: - case 5400: - cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01B0); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0120); - cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01B0); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0120); - if (ssc) - cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x0423); - break; - /* Setting VCO for 9.72GHz */ - case 1620: - case 2430: - case 3240: - cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0184); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xCCCD); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0104); - cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0184); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xCCCD); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0104); - if (ssc) - cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x03B9); - break; - /* Setting VCO for 8.64GHz */ - case 2160: - case 4320: - cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0159); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x999A); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00E7); - cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0159); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x999A); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00E7); - if (ssc) - cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x034F); - break; - /* Setting VCO for 8.1GHz */ - case 8100: - cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0144); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00D8); - cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0144); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00D8); - if (ssc) - cdns_torrent_dp_enable_ssc_25mhz(cdns_phy, 0x031A); - break; + ret = cdns_torrent_dp_verify_config(inst, &opts->dp); + if (ret) { + dev_err(&phy->dev, "invalid params for phy configure\n"); + return ret; } - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + if (opts->dp.set_lanes) { + ret = cdns_torrent_dp_set_lanes(cdns_phy, &opts->dp); + if (ret) { + dev_err(&phy->dev, "cdns_torrent_dp_set_lanes failed\n"); + return ret; + } + } - if (ssc) { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x0315); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x0315); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); - } else { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x0317); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x0317); - /* Set reset register values to disable SSC */ - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); + if (opts->dp.set_rate) { + ret = cdns_torrent_dp_set_rate(cdns_phy, &opts->dp); + if (ret) { + dev_err(&phy->dev, "cdns_torrent_dp_set_rate failed\n"); + return ret; + } } - cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x00C7); - cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_START, 0x00C7); - cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_REFCNT_START, 0x00C7); - cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7); + if (opts->dp.set_voltages) + cdns_torrent_dp_set_voltages(cdns_phy, &opts->dp); + + return ret; } -static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, - u32 rate, u32 num_lanes) +static int cdns_torrent_phy_on(struct phy *phy) { - unsigned int clk_sel_val = 0; - unsigned int hsclk_div_val = 0; - unsigned int i; + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + u32 read_val; + int ret; - /* 16'h0000 for single DP link configuration */ - regmap_field_write(cdns_phy->phy_pll_cfg, 0x0); + if (cdns_phy->nsubnodes == 1) { + /* Take the PHY lane group out of reset */ + reset_control_deassert(inst->lnk_rst); - switch (rate) { - case 1620: - clk_sel_val = 0x0f01; - hsclk_div_val = 2; - break; - case 2160: - case 2430: - case 2700: - clk_sel_val = 0x0701; - hsclk_div_val = 1; - break; - case 3240: - clk_sel_val = 0x0b00; - hsclk_div_val = 2; - break; - case 4320: - case 5400: - clk_sel_val = 0x0301; - hsclk_div_val = 0; - break; - case 8100: - clk_sel_val = 0x0200; - hsclk_div_val = 0; - break; + /* Take the PHY out of reset */ + ret = reset_control_deassert(cdns_phy->phy_rst); + if (ret) + return ret; + } + + /* + * Wait for cmn_ready assertion + * PHY_PMA_CMN_CTRL1[0] == 1 + */ + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1, + read_val, read_val, 1000, + PLL_LOCK_TIMEOUT); + if (ret) { + dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n"); + return ret; } - cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, - CMN_PDIAG_PLL0_CLK_SEL_M0, clk_sel_val); - cdns_torrent_phy_write(cdns_phy->regmap_common_cdb, - CMN_PDIAG_PLL1_CLK_SEL_M0, clk_sel_val); + mdelay(10); - /* PMA lane configuration to deal with multi-link operation */ - for (i = 0; i < num_lanes; i++) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[i], - XCVR_DIAG_HSCLK_DIV, hsclk_div_val); + return 0; } -static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, - unsigned int lane) +static int cdns_torrent_phy_off(struct phy *phy) { - /* Per lane, refclock-dependent receiver detection setting */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_RCVDET_ST_TMR, 0x0780); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_RCVDET_ST_TMR, 0x09C4); - - /* Writing Tx/Rx Power State Controllers registers */ - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A0, 0x00FB); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A2, 0x04AA); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A3, 0x04AA); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A0, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A2, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A3, 0x0000); + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + int ret; - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_CAL, 0x0000); + if (cdns_phy->nsubnodes != 1) + return 0; - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_GCSM1_CTRL, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_GCSM2_CTRL, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_PERGCSM_CTRL, 0x0000); + ret = reset_control_assert(cdns_phy->phy_rst); + if (ret) + return ret; - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_BIDI_CTRL, 0x000F); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_PLLDRC_CTRL, 0x0001); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_HSCLK_SEL, 0x0000); + return reset_control_assert(inst->lnk_rst); } -static int cdns_torrent_dp_set_power_state(struct cdns_torrent_phy *cdns_phy, - u32 num_lanes, - enum phy_powerstate powerstate) +static int cdns_torrent_dp_init(struct phy *phy) { - /* Register value for power state for a single byte. */ - u32 value_part; - u32 value; - u32 mask; - u32 read_val; - u32 ret; + unsigned char lane_bits; + int ret; + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - switch (powerstate) { - case (POWERSTATE_A0): - value_part = 0x01U; - break; - case (POWERSTATE_A2): - value_part = 0x04U; - break; - default: - /* Powerstate A3 */ - value_part = 0x08U; - break; - } - - /* Select values of registers and mask, depending on enabled - * lane count. - */ - switch (num_lanes) { - /* lane 0 */ - case (1): - value = value_part; - mask = 0x0000003FU; - break; - /* lanes 0-1 */ - case (2): - value = (value_part - | (value_part << 8)); - mask = 0x00003F3FU; + switch (cdns_phy->ref_clk_rate) { + case REF_CLK_19_2MHZ: + case REF_CLK_25MHZ: + /* Valid Ref Clock Rate */ break; - /* lanes 0-3, all */ default: - value = (value_part - | (value_part << 8) - | (value_part << 16) - | (value_part << 24)); - mask = 0x3F3F3F3FU; - break; + dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); + return -EINVAL; } - /* Set power state A. */ - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, value); - /* Wait, until PHY acknowledges power state completion. */ - ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_POWER_STATE_ACK, - read_val, (read_val & mask) == value, 0, - POLL_TIMEOUT_US); - cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_POWER_STATE_REQ, 0x00000000); - ndelay(100); + cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ - return ret; -} + /* PHY PMA registers configuration function */ + cdns_torrent_dp_pma_cfg(cdns_phy, inst); -static int cdns_torrent_dp_run(struct cdns_torrent_phy *cdns_phy, u32 num_lanes) -{ - unsigned int read_val; - int ret; - struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; + /* + * Set lines power state to A0 + * Set lines pll clk enable to 0 + */ + cdns_torrent_dp_set_a0_pll(cdns_phy, inst->num_lanes); /* - * waiting for ACK of pma_xcvr_pllclk_en_ln_*, only for the - * master lane + * release phy_l0*_reset_n and pma_tx_elec_idle_ln_* based on + * used lanes */ - ret = regmap_read_poll_timeout(regmap, PHY_PMA_XCVR_PLLCLK_EN_ACK, - read_val, read_val & 1, - 0, POLL_TIMEOUT_US); - if (ret == -ETIMEDOUT) { - dev_err(cdns_phy->dev, - "timeout waiting for link PLL clock enable ack\n"); - return ret; - } + lane_bits = (1 << inst->num_lanes) - 1; + cdns_torrent_dp_write(regmap, PHY_RESET, + ((0xF & ~lane_bits) << 4) | (0xF & lane_bits)); - ndelay(100); + /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ + cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); - ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, - POWERSTATE_A2); + /* PHY PMA registers configuration functions */ + /* Initialize PHY with max supported link rate, without SSC. */ + if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, + cdns_phy->max_bit_rate, + false); + else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, + cdns_phy->max_bit_rate, + false); + cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, + inst->num_lanes); + + /* take out of reset */ + regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1); + + cdns_torrent_phy_on(phy); + + ret = cdns_torrent_dp_wait_pma_cmn_ready(cdns_phy); if (ret) return ret; - ret = cdns_torrent_dp_set_power_state(cdns_phy, num_lanes, - POWERSTATE_A0); + ret = cdns_torrent_dp_run(cdns_phy, inst->num_lanes); return ret; } @@ -1764,56 +1762,6 @@ static int cdns_torrent_derived_refclk_register(struct cdns_torrent_phy *cdns_ph return 0; } -static int cdns_torrent_phy_on(struct phy *phy) -{ - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - u32 read_val; - int ret; - - if (cdns_phy->nsubnodes == 1) { - /* Take the PHY lane group out of reset */ - reset_control_deassert(inst->lnk_rst); - - /* Take the PHY out of reset */ - ret = reset_control_deassert(cdns_phy->phy_rst); - if (ret) - return ret; - } - - /* - * Wait for cmn_ready assertion - * PHY_PMA_CMN_CTRL1[0] == 1 - */ - ret = regmap_field_read_poll_timeout(cdns_phy->phy_pma_cmn_ctrl_1, - read_val, read_val, 1000, - PLL_LOCK_TIMEOUT); - if (ret) { - dev_err(cdns_phy->dev, "Timeout waiting for CMN ready\n"); - return ret; - } - - mdelay(10); - - return 0; -} - -static int cdns_torrent_phy_off(struct phy *phy) -{ - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); - int ret; - - if (cdns_phy->nsubnodes != 1) - return 0; - - ret = reset_control_assert(cdns_phy->phy_rst); - if (ret) - return ret; - - return reset_control_assert(inst->lnk_rst); -} - static struct regmap *cdns_regmap_init(struct device *dev, void __iomem *base, u32 block_offset, u8 reg_offset_shift, @@ -2091,6 +2039,27 @@ static int cdns_torrent_phy_init(struct phy *phy) return 0; } +static const struct phy_ops cdns_torrent_phy_ops = { + .init = cdns_torrent_phy_init, + .configure = cdns_torrent_dp_configure, + .power_on = cdns_torrent_phy_on, + .power_off = cdns_torrent_phy_off, + .owner = THIS_MODULE, +}; + +static int cdns_torrent_noop_phy_on(struct phy *phy) +{ + /* Give 5ms to 10ms delay for the PIPE clock to be stable */ + usleep_range(5000, 10000); + + return 0; +} + +static const struct phy_ops noop_ops = { + .power_on = cdns_torrent_noop_phy_on, + .owner = THIS_MODULE, +}; + static int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { -- cgit v1.2.3 From 3b40162516ca04209d750ddc174eea3e6deac148 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:48 +0200 Subject: phy: cadence-torrent: Add enum for supported input reference clock frequencies Torrent PHY supports different input reference clock frequencies. Register configurations will be different based on reference clock value. Prepare driver to support such multiple reference clock frequencies. Signed-off-by: Swapnil Jakhade Reviewed-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210728145454.15945-4-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 51 +++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 4b2d6d3eace9..f746553c8089 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -26,11 +26,13 @@ #define REF_CLK_19_2MHZ 19200000 #define REF_CLK_25MHZ 25000000 +#define REF_CLK_100MHZ 100000000 #define MAX_NUM_LANES 4 #define DEFAULT_MAX_BIT_RATE 8100 /* in Mbps */ #define NUM_SSC_MODE 3 +#define NUM_REF_CLK 3 #define NUM_PHY_TYPE 6 #define POLL_TIMEOUT_US 5000 @@ -273,6 +275,12 @@ enum cdns_torrent_phy_type { TYPE_USB, }; +enum cdns_torrent_ref_clk { + CLK_19_2_MHZ, + CLK_25_MHZ, + CLK_100_MHZ +}; + enum cdns_torrent_ssc_mode { NO_SSC, EXTERNAL_SSC, @@ -296,7 +304,7 @@ struct cdns_torrent_phy { struct reset_control *apb_rst; struct device *dev; struct clk *clk; - unsigned long ref_clk_rate; + enum cdns_torrent_ref_clk ref_clk_rate; struct cdns_torrent_inst phys[MAX_NUM_LANES]; int nsubnodes; const struct cdns_torrent_data *init_data; @@ -960,10 +968,10 @@ static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, unsigned int lane) { /* Per lane, refclock-dependent receiver detection setting */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], TX_RCVDET_ST_TMR, 0x0780); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], TX_RCVDET_ST_TMR, 0x09C4); @@ -1004,10 +1012,10 @@ static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, { unsigned int i; - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) /* PMA common configuration 19.2MHz */ cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) /* PMA common configuration 25MHz */ cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); @@ -1254,12 +1262,12 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, ndelay(200); /* DP Rate Change - VCO Output settings. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) { + if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) { /* PMA common configuration 19.2MHz */ cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, dp->ssc); cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - } else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) { + } else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) { /* PMA common configuration 25MHz */ cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, dp->ssc); @@ -1602,8 +1610,8 @@ static int cdns_torrent_dp_init(struct phy *phy) struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; switch (cdns_phy->ref_clk_rate) { - case REF_CLK_19_2MHZ: - case REF_CLK_25MHZ: + case CLK_19_2_MHZ: + case CLK_25_MHZ: /* Valid Ref Clock Rate */ break; default: @@ -1635,11 +1643,11 @@ static int cdns_torrent_dp_init(struct phy *phy) /* PHY PMA registers configuration functions */ /* Initialize PHY with max supported link rate, without SSC. */ - if (cdns_phy->ref_clk_rate == REF_CLK_19_2MHZ) + if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, cdns_phy->max_bit_rate, false); - else if (cdns_phy->ref_clk_rate == REF_CLK_25MHZ) + else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, cdns_phy->max_bit_rate, false); @@ -2255,6 +2263,7 @@ static int cdns_torrent_reset(struct cdns_torrent_phy *cdns_phy) static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) { struct device *dev = cdns_phy->dev; + unsigned long ref_clk_rate; int ret; cdns_phy->clk = devm_clk_get(dev, "refclk"); @@ -2269,13 +2278,29 @@ static int cdns_torrent_clk(struct cdns_torrent_phy *cdns_phy) return ret; } - cdns_phy->ref_clk_rate = clk_get_rate(cdns_phy->clk); - if (!(cdns_phy->ref_clk_rate)) { + ref_clk_rate = clk_get_rate(cdns_phy->clk); + if (!ref_clk_rate) { dev_err(cdns_phy->dev, "Failed to get ref clock rate\n"); clk_disable_unprepare(cdns_phy->clk); return -EINVAL; } + switch (ref_clk_rate) { + case REF_CLK_19_2MHZ: + cdns_phy->ref_clk_rate = CLK_19_2_MHZ; + break; + case REF_CLK_25MHZ: + cdns_phy->ref_clk_rate = CLK_25_MHZ; + break; + case REF_CLK_100MHZ: + cdns_phy->ref_clk_rate = CLK_100_MHZ; + break; + default: + dev_err(cdns_phy->dev, "Invalid Ref Clock Rate\n"); + clk_disable_unprepare(cdns_phy->clk); + return -EINVAL; + } + return 0; } -- cgit v1.2.3 From 6a2338a5bf7f9b4df5ed55d7b25ceb996ea09310 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:49 +0200 Subject: phy: cadence-torrent: Configure PHY registers as a function of input reference clock rate Torrent PHY supports multiple serdes standards with different input reference clock frequencies. PHY register values differ based on the reference clock rate. Add PHY input reference clock frequency as a new dimension to select proper register configuration. No functional change is intended. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-5-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 830 +++++++++++++++--------------- 1 file changed, 422 insertions(+), 408 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index f746553c8089..86f05817704d 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -360,12 +360,12 @@ struct cdns_torrent_data { [NUM_SSC_MODE]; struct cdns_torrent_vals *pcs_cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] [NUM_SSC_MODE]; - struct cdns_torrent_vals *cmn_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *tx_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; - struct cdns_torrent_vals *rx_ln_vals[NUM_PHY_TYPE][NUM_PHY_TYPE] - [NUM_SSC_MODE]; + struct cdns_torrent_vals *cmn_vals[NUM_REF_CLK][NUM_PHY_TYPE] + [NUM_PHY_TYPE][NUM_SSC_MODE]; + struct cdns_torrent_vals *tx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE] + [NUM_PHY_TYPE][NUM_SSC_MODE]; + struct cdns_torrent_vals *rx_ln_vals[NUM_REF_CLK][NUM_PHY_TYPE] + [NUM_PHY_TYPE][NUM_SSC_MODE]; }; struct cdns_regmap_cdb_context { @@ -1943,6 +1943,7 @@ static int cdns_torrent_phy_init(struct phy *phy) struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); const struct cdns_torrent_data *init_data = cdns_phy->init_data; struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; struct cdns_torrent_inst *inst = phy_get_drvdata(phy); enum cdns_torrent_phy_type phy_type = inst->phy_type; @@ -2008,7 +2009,7 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA common registers configurations */ - cmn_vals = init_data->cmn_vals[phy_type][TYPE_NONE][ssc]; + cmn_vals = init_data->cmn_vals[ref_clk][phy_type][TYPE_NONE][ssc]; if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; num_regs = cmn_vals->num_regs; @@ -2019,7 +2020,7 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA TX lane registers configurations */ - tx_ln_vals = init_data->tx_ln_vals[phy_type][TYPE_NONE][ssc]; + tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc]; if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; num_regs = tx_ln_vals->num_regs; @@ -2032,7 +2033,7 @@ static int cdns_torrent_phy_init(struct phy *phy) } /* PMA RX lane registers configurations */ - rx_ln_vals = init_data->rx_ln_vals[phy_type][TYPE_NONE][ssc]; + rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_type][TYPE_NONE][ssc]; if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; num_regs = rx_ln_vals->num_regs; @@ -2073,6 +2074,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) { const struct cdns_torrent_data *init_data = cdns_phy->init_data; struct cdns_torrent_vals *cmn_vals, *tx_ln_vals, *rx_ln_vals; + enum cdns_torrent_ref_clk ref_clk = cdns_phy->ref_clk_rate; struct cdns_torrent_vals *link_cmn_vals, *xcvr_diag_vals; enum cdns_torrent_phy_type phy_t1, phy_t2, tmp_phy_type; struct cdns_torrent_vals *pcs_cmn_vals; @@ -2161,7 +2163,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA common registers configurations */ - cmn_vals = init_data->cmn_vals[phy_t1][phy_t2][ssc]; + cmn_vals = init_data->cmn_vals[ref_clk][phy_t1][phy_t2][ssc]; if (cmn_vals) { reg_pairs = cmn_vals->reg_pairs; num_regs = cmn_vals->num_regs; @@ -2172,7 +2174,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA TX lane registers configurations */ - tx_ln_vals = init_data->tx_ln_vals[phy_t1][phy_t2][ssc]; + tx_ln_vals = init_data->tx_ln_vals[ref_clk][phy_t1][phy_t2][ssc]; if (tx_ln_vals) { reg_pairs = tx_ln_vals->reg_pairs; num_regs = tx_ln_vals->num_regs; @@ -2185,7 +2187,7 @@ int cdns_torrent_phy_configure_multilink(struct cdns_torrent_phy *cdns_phy) } /* PMA RX lane registers configurations */ - rx_ln_vals = init_data->rx_ln_vals[phy_t1][phy_t2][ssc]; + rx_ln_vals = init_data->rx_ln_vals[ref_clk][phy_t1][phy_t2][ssc]; if (rx_ln_vals) { reg_pairs = rx_ln_vals->reg_pairs; num_regs = rx_ln_vals->num_regs; @@ -3481,230 +3483,236 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, .cmn_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, }, [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, }, }, }, .tx_ln_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_SGMII] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_QSGMII] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_USB] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, }, [TYPE_SGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [TYPE_NONE] = { + [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [TYPE_NONE] = { + [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, }, }, }, .rx_ln_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, }, [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, }, }, }, @@ -3890,230 +3898,236 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, .cmn_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = &sl_pcie_100_int_ssc_cmn_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &pcie_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + }, }, [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &pcie_100_int_ssc_cmn_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_sgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_qsgmii_100_no_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_int_ssc_cmn_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_cmn_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, - [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + [TYPE_NONE] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &usb_100_int_ssc_cmn_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [EXTERNAL_SSC] = &sl_usb_100_no_ssc_cmn_vals, + [INTERNAL_SSC] = &sl_usb_100_int_ssc_cmn_vals, + }, }, }, }, .tx_ln_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_SGMII] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_QSGMII] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, + [TYPE_USB] = { + [NO_SSC] = NULL, + [EXTERNAL_SSC] = NULL, + [INTERNAL_SSC] = NULL, + }, }, [TYPE_SGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [TYPE_NONE] = { + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, + [TYPE_NONE] = { + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = NULL, - [EXTERNAL_SSC] = NULL, - [INTERNAL_SSC] = NULL, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_sgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &ti_qsgmii_100_no_ssc_tx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &usb_100_no_ssc_tx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_tx_ln_vals, + }, }, }, }, .rx_ln_vals = { - [TYPE_PCIE] = { - [TYPE_NONE] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [CLK_100_MHZ] = { + [TYPE_PCIE] = { + [TYPE_NONE] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + }, }, [TYPE_SGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + }, }, [TYPE_QSGMII] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &pcie_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_SGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, + [TYPE_USB] = { + [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, + }, }, [TYPE_USB] = { - [NO_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &sgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_QSGMII] = { - [TYPE_NONE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - [TYPE_USB] = { - [NO_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &qsgmii_100_no_ssc_rx_ln_vals, - }, - }, - [TYPE_USB] = { - [TYPE_NONE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_PCIE] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_SGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - }, - [TYPE_QSGMII] = { - [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, - [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, - [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [TYPE_NONE] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_PCIE] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_SGMII] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, + [TYPE_QSGMII] = { + [NO_SSC] = &usb_100_no_ssc_rx_ln_vals, + [EXTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + [INTERNAL_SSC] = &usb_100_no_ssc_rx_ln_vals, + }, }, }, }, -- cgit v1.2.3 From da055e5503893e27d6494f52bd6987f0da0c7658 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:50 +0200 Subject: phy: cadence-torrent: Add PHY registers for DP in array format Add PHY registers for single link DP in array format to simplify code and to improve readability. This supports already supported frequencies for DP of 19.2MHz and 25MHz. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-6-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 622 ++++++++++++++++-------------- 1 file changed, 334 insertions(+), 288 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 86f05817704d..a6331927d775 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -572,50 +572,6 @@ static const struct coefficients vltg_coeff[4][4] = { } }; -static -void cdns_torrent_dp_pma_cmn_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy) -{ - struct regmap *regmap = cdns_phy->regmap_common_cdb; - - /* refclock registers - assumes 19.2 MHz refclock */ - cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0014); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0027); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00A1); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0027); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00A1); - cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x0060); - cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x0060); - cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0014); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x0018); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x0018); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x0240); - cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0005); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000B); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x0137); - - /* PLL registers */ - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00C0); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00C0); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0260); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0260); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); -} - /* * Set registers responsible for enabling and configuring SSC, with second and * third register values provided by parameters. @@ -647,148 +603,88 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, /* Setting VCO for 10.8GHz */ case 2700: case 5400: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x0119); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x00BC); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0012); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x0119); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x00BC); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0012); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0119); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x00BC); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0012); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0119); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x00BC); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0012); if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A, - 0x006A); + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x033A, 0x006A); break; /* Setting VCO for 9.72GHz */ case 1620: case 2430: case 3240: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01FA); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x0152); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01FA); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x4000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x0152); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01FA); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0152); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01FA); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x4000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0152); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD, - 0x0069); + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x05DD, 0x0069); break; /* Setting VCO for 8.64GHz */ case 2160: case 4320: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01C2); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x012C); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01C2); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x012C); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01C2); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x012C); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01C2); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x012C); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536, - 0x0069); + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x0536, 0x0069); break; /* Setting VCO for 8.1GHz */ case 8100: - cdns_torrent_phy_write(regmap, - CMN_PLL0_INTDIV_M0, 0x01A5); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVL_M0, 0xE000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_HIGH_THR_M0, 0x011A); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL0_CTRL_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_INTDIV_M0, 0x01A5); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVL_M0, 0xE000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_FRACDIVH_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_HIGH_THR_M0, 0x011A); - cdns_torrent_phy_write(regmap, - CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x01A5); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0xE000); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x011A); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x01A5); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0xE000); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x011A); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); if (ssc) - cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7, - 0x006A); + cdns_torrent_dp_enable_ssc_19_2mhz(cdns_phy, 0x04D7, 0x006A); break; } if (ssc) { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_PLLCNT_START, 0x025E); + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_THR, 0x0005); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_PLLCNT_START, 0x025E); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_THR, 0x0005); } else { - cdns_torrent_phy_write(regmap, - CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260); - cdns_torrent_phy_write(regmap, - CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260); + cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_PLLCNT_START, 0x0260); + cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_PLLCNT_START, 0x0260); /* Set reset register values to disable SSC */ - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL1_M0, 0x0002); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL2_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL3_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_SS_CTRL4_M0, 0x0000); - cdns_torrent_phy_write(regmap, - CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_PLLCNT_THR, 0x0003); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL1_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL2_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL3_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_SS_CTRL4_M0, 0x0000); + cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_THR, 0x0003); } cdns_torrent_phy_write(regmap, CMN_PLL0_LOCK_REFCNT_START, 0x0099); @@ -797,50 +693,6 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(struct cdns_torrent_phy *cdns_phy, cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x0099); } -static -void cdns_torrent_dp_pma_cmn_cfg_25mhz(struct cdns_torrent_phy *cdns_phy) -{ - struct regmap *regmap = cdns_phy->regmap_common_cdb; - - /* refclock registers - assumes 25 MHz refclock */ - cdns_torrent_phy_write(regmap, CMN_SSM_BIAS_TMR, 0x0019); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLPRE_TMR, 0x0032); - cdns_torrent_phy_write(regmap, CMN_PLLSM0_PLLLOCK_TMR, 0x00D1); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLPRE_TMR, 0x0032); - cdns_torrent_phy_write(regmap, CMN_PLLSM1_PLLLOCK_TMR, 0x00D1); - cdns_torrent_phy_write(regmap, CMN_BGCAL_INIT_TMR, 0x007D); - cdns_torrent_phy_write(regmap, CMN_BGCAL_ITER_TMR, 0x007D); - cdns_torrent_phy_write(regmap, CMN_IBCAL_INIT_TMR, 0x0019); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_INIT_TMR, 0x001E); - cdns_torrent_phy_write(regmap, CMN_TXPUCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_INIT_TMR, 0x001E); - cdns_torrent_phy_write(regmap, CMN_TXPDCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_RXCAL_INIT_TMR, 0x02EE); - cdns_torrent_phy_write(regmap, CMN_RXCAL_ITER_TMR, 0x0006); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_INIT_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_ITER_TMR, 0x0002); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_REFTIM_START, 0x000E); - cdns_torrent_phy_write(regmap, CMN_SD_CAL_PLLCNT_START, 0x012B); - - /* PLL registers */ - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); - cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); - cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_INIT_TMR, 0x00FA); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_INIT_TMR, 0x00FA); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_ITER_TMR, 0x0004); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_REFTIM_START, 0x0317); - cdns_torrent_phy_write(regmap, CMN_PLL0_VCOCAL_TCTRL, 0x0003); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_REFTIM_START, 0x0317); - cdns_torrent_phy_write(regmap, CMN_PLL1_VCOCAL_TCTRL, 0x0003); -} - /* * Set registers responsible for enabling and configuring SSC, with second * register value provided by a parameter. @@ -964,66 +816,6 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7); } -static void cdns_torrent_dp_pma_lane_cfg(struct cdns_torrent_phy *cdns_phy, - unsigned int lane) -{ - /* Per lane, refclock-dependent receiver detection setting */ - if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_RCVDET_ST_TMR, 0x0780); - else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_RCVDET_ST_TMR, 0x09C4); - - /* Writing Tx/Rx Power State Controllers registers */ - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A0, 0x00FB); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A2, 0x04AA); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - TX_PSC_A3, 0x04AA); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A0, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A2, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_A3, 0x0000); - - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_PSC_CAL, 0x0000); - - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_GCSM1_CTRL, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_GCSM2_CTRL, 0x0000); - cdns_torrent_phy_write(cdns_phy->regmap_rx_lane_cdb[lane], - RX_REE_PERGCSM_CTRL, 0x0000); - - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_BIDI_CTRL, 0x000F); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_PLLDRC_CTRL, 0x0001); - cdns_torrent_phy_write(cdns_phy->regmap_tx_lane_cdb[lane], - XCVR_DIAG_HSCLK_SEL, 0x0000); -} - -static void cdns_torrent_dp_pma_cfg(struct cdns_torrent_phy *cdns_phy, - struct cdns_torrent_inst *inst) -{ - unsigned int i; - - if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) - /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) - /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - - /* PMA lane configuration to deal with multi-link operation */ - for (i = 0; i < inst->num_lanes; i++) - cdns_torrent_dp_pma_lane_cfg(cdns_phy, i); -} - /* * Enable or disable PLL for selected lanes. */ @@ -1196,9 +988,6 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, unsigned int hsclk_div_val = 0; unsigned int i; - /* 16'h0000 for single DP link configuration */ - regmap_field_write(cdns_phy->phy_pll_cfg, 0x0); - switch (rate) { case 1620: clk_sel_val = 0x0f01; @@ -1243,8 +1032,7 @@ static void cdns_torrent_dp_pma_cmn_rate(struct cdns_torrent_phy *cdns_phy, static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, struct phy_configure_opts_dp *dp) { - u32 ret; - u32 read_val; + u32 read_val, ret; /* Disable the cmn_pll0_en before re-programming the new data rate. */ regmap_field_write(cdns_phy->phy_pma_pll_raw_ctrl, 0x0); @@ -1262,17 +1050,12 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, ndelay(200); /* DP Rate Change - VCO Output settings. */ - if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) { + if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) /* PMA common configuration 19.2MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_19_2mhz(cdns_phy); - } else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) { + cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, dp->link_rate, dp->ssc); + else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) /* PMA common configuration 25MHz */ - cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, - dp->ssc); - cdns_torrent_dp_pma_cmn_cfg_25mhz(cdns_phy); - } + cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, dp->ssc); cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); /* Enable the cmn_pll0_en. */ @@ -1621,9 +1404,6 @@ static int cdns_torrent_dp_init(struct phy *phy) cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ - /* PHY PMA registers configuration function */ - cdns_torrent_dp_pma_cfg(cdns_phy, inst); - /* * Set lines power state to A0 * Set lines pll clk enable to 0 @@ -1957,9 +1737,6 @@ static int cdns_torrent_phy_init(struct phy *phy) if (cdns_phy->nsubnodes > 1) return 0; - if (phy_type == TYPE_DP) - return cdns_torrent_dp_init(phy); - /** * Spread spectrum generation is not required or supported * for SGMII/QSGMII @@ -2045,6 +1822,9 @@ static int cdns_torrent_phy_init(struct phy *phy) } } + if (phy_type == TYPE_DP) + return cdns_torrent_dp_init(phy); + return 0; } @@ -2569,6 +2349,168 @@ static int cdns_torrent_phy_remove(struct platform_device *pdev) return 0; } +/* Single DisplayPort(DP) link configuration */ +static struct cdns_reg_pairs sl_dp_link_cmn_regs[] = { + {0x0000, PHY_PLL_CFG}, +}; + +static struct cdns_reg_pairs sl_dp_xcvr_diag_ln_regs[] = { + {0x0000, XCVR_DIAG_HSCLK_SEL}, + {0x0001, XCVR_DIAG_PLLDRC_CTRL} +}; + +static struct cdns_torrent_vals sl_dp_link_cmn_vals = { + .reg_pairs = sl_dp_link_cmn_regs, + .num_regs = ARRAY_SIZE(sl_dp_link_cmn_regs), +}; + +static struct cdns_torrent_vals sl_dp_xcvr_diag_ln_vals = { + .reg_pairs = sl_dp_xcvr_diag_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_xcvr_diag_ln_regs), +}; + +/* Single DP, 19.2 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs sl_dp_19_2_no_ssc_cmn_regs[] = { + {0x0014, CMN_SSM_BIAS_TMR}, + {0x0027, CMN_PLLSM0_PLLPRE_TMR}, + {0x00A1, CMN_PLLSM0_PLLLOCK_TMR}, + {0x0027, CMN_PLLSM1_PLLPRE_TMR}, + {0x00A1, CMN_PLLSM1_PLLLOCK_TMR}, + {0x0060, CMN_BGCAL_INIT_TMR}, + {0x0060, CMN_BGCAL_ITER_TMR}, + {0x0014, CMN_IBCAL_INIT_TMR}, + {0x0018, CMN_TXPUCAL_INIT_TMR}, + {0x0005, CMN_TXPUCAL_ITER_TMR}, + {0x0018, CMN_TXPDCAL_INIT_TMR}, + {0x0005, CMN_TXPDCAL_ITER_TMR}, + {0x0240, CMN_RXCAL_INIT_TMR}, + {0x0005, CMN_RXCAL_ITER_TMR}, + {0x0002, CMN_SD_CAL_INIT_TMR}, + {0x0002, CMN_SD_CAL_ITER_TMR}, + {0x000B, CMN_SD_CAL_REFTIM_START}, + {0x0137, CMN_SD_CAL_PLLCNT_START}, + {0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0}, + {0x0F00, CMN_PDIAG_PLL0_CP_IADJ_M0}, + {0x0F08, CMN_PDIAG_PLL0_FILT_PADJ_M0}, + {0x0004, CMN_PLL0_DSM_DIAG_M0}, + {0x0509, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0F00, CMN_PDIAG_PLL1_CP_IADJ_M0}, + {0x0F08, CMN_PDIAG_PLL1_FILT_PADJ_M0}, + {0x0004, CMN_PLL1_DSM_DIAG_M0}, + {0x00C0, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0004, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x00C0, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0004, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x0260, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0260, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_reg_pairs sl_dp_19_2_no_ssc_tx_ln_regs[] = { + {0x0780, TX_RCVDET_ST_TMR}, + {0x00FB, TX_PSC_A0}, + {0x04AA, TX_PSC_A2}, + {0x04AA, TX_PSC_A3}, + {0x000F, XCVR_DIAG_BIDI_CTRL} +}; + +static struct cdns_reg_pairs sl_dp_19_2_no_ssc_rx_ln_regs[] = { + {0x0000, RX_PSC_A0}, + {0x0000, RX_PSC_A2}, + {0x0000, RX_PSC_A3}, + {0x0000, RX_PSC_CAL}, + {0x0000, RX_REE_GCSM1_CTRL}, + {0x0000, RX_REE_GCSM2_CTRL}, + {0x0000, RX_REE_PERGCSM_CTRL} +}; + +static struct cdns_torrent_vals sl_dp_19_2_no_ssc_cmn_vals = { + .reg_pairs = sl_dp_19_2_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals sl_dp_19_2_no_ssc_tx_ln_vals = { + .reg_pairs = sl_dp_19_2_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals sl_dp_19_2_no_ssc_rx_ln_vals = { + .reg_pairs = sl_dp_19_2_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_19_2_no_ssc_rx_ln_regs), +}; + +/* Single DP, 25 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs sl_dp_25_no_ssc_cmn_regs[] = { + {0x0019, CMN_SSM_BIAS_TMR}, + {0x0032, CMN_PLLSM0_PLLPRE_TMR}, + {0x00D1, CMN_PLLSM0_PLLLOCK_TMR}, + {0x0032, CMN_PLLSM1_PLLPRE_TMR}, + {0x00D1, CMN_PLLSM1_PLLLOCK_TMR}, + {0x007D, CMN_BGCAL_INIT_TMR}, + {0x007D, CMN_BGCAL_ITER_TMR}, + {0x0019, CMN_IBCAL_INIT_TMR}, + {0x001E, CMN_TXPUCAL_INIT_TMR}, + {0x0006, CMN_TXPUCAL_ITER_TMR}, + {0x001E, CMN_TXPDCAL_INIT_TMR}, + {0x0006, CMN_TXPDCAL_ITER_TMR}, + {0x02EE, CMN_RXCAL_INIT_TMR}, + {0x0006, CMN_RXCAL_ITER_TMR}, + {0x0002, CMN_SD_CAL_INIT_TMR}, + {0x0002, CMN_SD_CAL_ITER_TMR}, + {0x000E, CMN_SD_CAL_REFTIM_START}, + {0x012B, CMN_SD_CAL_PLLCNT_START}, + {0x0509, CMN_PDIAG_PLL0_CP_PADJ_M0}, + {0x0F00, CMN_PDIAG_PLL0_CP_IADJ_M0}, + {0x0F08, CMN_PDIAG_PLL0_FILT_PADJ_M0}, + {0x0004, CMN_PLL0_DSM_DIAG_M0}, + {0x0509, CMN_PDIAG_PLL1_CP_PADJ_M0}, + {0x0F00, CMN_PDIAG_PLL1_CP_IADJ_M0}, + {0x0F08, CMN_PDIAG_PLL1_FILT_PADJ_M0}, + {0x0004, CMN_PLL1_DSM_DIAG_M0}, + {0x00FA, CMN_PLL0_VCOCAL_INIT_TMR}, + {0x0004, CMN_PLL0_VCOCAL_ITER_TMR}, + {0x00FA, CMN_PLL1_VCOCAL_INIT_TMR}, + {0x0004, CMN_PLL1_VCOCAL_ITER_TMR}, + {0x0317, CMN_PLL0_VCOCAL_REFTIM_START}, + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0317, CMN_PLL1_VCOCAL_REFTIM_START}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_reg_pairs sl_dp_25_no_ssc_tx_ln_regs[] = { + {0x09C4, TX_RCVDET_ST_TMR}, + {0x00FB, TX_PSC_A0}, + {0x04AA, TX_PSC_A2}, + {0x04AA, TX_PSC_A3}, + {0x000F, XCVR_DIAG_BIDI_CTRL} +}; + +static struct cdns_reg_pairs sl_dp_25_no_ssc_rx_ln_regs[] = { + {0x0000, RX_PSC_A0}, + {0x0000, RX_PSC_A2}, + {0x0000, RX_PSC_A3}, + {0x0000, RX_PSC_CAL}, + {0x0000, RX_REE_GCSM1_CTRL}, + {0x0000, RX_REE_GCSM2_CTRL}, + {0x0000, RX_REE_PERGCSM_CTRL} +}; + +static struct cdns_torrent_vals sl_dp_25_no_ssc_cmn_vals = { + .reg_pairs = sl_dp_25_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals sl_dp_25_no_ssc_tx_ln_vals = { + .reg_pairs = sl_dp_25_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals sl_dp_25_no_ssc_rx_ln_vals = { + .reg_pairs = sl_dp_25_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_rx_ln_regs), +}; + /* USB and SGMII/QSGMII link configuration */ static struct cdns_reg_pairs usb_sgmii_link_cmn_regs[] = { {0x0002, PHY_PLL_CFG}, @@ -3307,6 +3249,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { .block_offset_shift = 0x2, .reg_offset_shift = 0x2, .link_cmn_vals = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_link_cmn_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3383,6 +3330,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, .xcvr_diag_vals = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_xcvr_diag_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3483,6 +3435,20 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, .cmn_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_cmn_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { @@ -3561,6 +3527,20 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, .tx_ln_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { @@ -3639,6 +3619,20 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, .rx_ln_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { @@ -3722,6 +3716,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { .block_offset_shift = 0x0, .reg_offset_shift = 0x1, .link_cmn_vals = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_link_cmn_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3798,6 +3797,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, .xcvr_diag_vals = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_xcvr_diag_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3898,6 +3902,20 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, .cmn_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_cmn_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_cmn_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { @@ -3976,6 +3994,20 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, .tx_ln_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_tx_ln_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_tx_ln_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { @@ -4054,6 +4086,20 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, .rx_ln_vals = { + [CLK_19_2_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_19_2_no_ssc_rx_ln_vals, + }, + }, + }, + [CLK_25_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_25_no_ssc_rx_ln_vals, + }, + }, + }, [CLK_100_MHZ] = { [TYPE_PCIE] = { [TYPE_NONE] = { -- cgit v1.2.3 From 1cc455150b7a67f3bbfe1dce03a97b4ae88778d5 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:51 +0200 Subject: phy: cadence-torrent: Add PHY configuration for DP with 100MHz ref clock Add PHY configuration registers for single link DP with 100MHz reference clock and NO_SSC. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-7-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 162 ++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index a6331927d775..69466481af26 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -103,6 +103,7 @@ #define CMN_PLL0_FRACDIVH_M0 0x0092U #define CMN_PLL0_HIGH_THR_M0 0x0093U #define CMN_PLL0_DSM_DIAG_M0 0x0094U +#define CMN_PLL0_DSM_FBH_OVRD_M0 0x0095U #define CMN_PLL0_SS_CTRL1_M0 0x0098U #define CMN_PLL0_SS_CTRL2_M0 0x0099U #define CMN_PLL0_SS_CTRL3_M0 0x009AU @@ -816,6 +817,89 @@ void cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(struct cdns_torrent_phy *cdns_phy, cdns_torrent_phy_write(regmap, CMN_PLL1_LOCK_PLLCNT_START, 0x00C7); } +static +void cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(struct cdns_torrent_phy *cdns_phy, + u32 rate, bool ssc) +{ + struct regmap *regmap = cdns_phy->regmap_common_cdb; + + /* Assumes 100 MHz refclock */ + switch (rate) { + /* Setting VCO for 10.8GHz */ + case 2700: + case 5400: + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0028); + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_FBH_OVRD_M0, 0x0022); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBH_OVRD_M0, 0x0022); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_FBL_OVRD_M0, 0x000C); + break; + /* Setting VCO for 9.72GHz */ + case 1620: + case 2430: + case 3240: + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0061); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0061); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x3333); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x3333); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0042); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0042); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + break; + /* Setting VCO for 8.64GHz */ + case 2160: + case 4320: + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0056); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0056); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVL_M0, 0x6666); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVL_M0, 0x6666); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x003A); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x003A); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + break; + /* Setting VCO for 8.1GHz */ + case 8100: + cdns_torrent_phy_write(regmap, CMN_PLL0_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PLL1_DSM_DIAG_M0, 0x0004); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_PADJ_M0, 0x0509); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CP_IADJ_M0, 0x0F00); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_FILT_PADJ_M0, 0x0F08); + cdns_torrent_phy_write(regmap, CMN_PLL0_INTDIV_M0, 0x0051); + cdns_torrent_phy_write(regmap, CMN_PLL1_INTDIV_M0, 0x0051); + cdns_torrent_phy_write(regmap, CMN_PLL0_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL1_FRACDIVH_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PLL0_HIGH_THR_M0, 0x0036); + cdns_torrent_phy_write(regmap, CMN_PLL1_HIGH_THR_M0, 0x0036); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL0_CTRL_M0, 0x0002); + cdns_torrent_phy_write(regmap, CMN_PDIAG_PLL1_CTRL_M0, 0x0002); + break; + } +} + /* * Enable or disable PLL for selected lanes. */ @@ -1056,6 +1140,10 @@ static int cdns_torrent_dp_configure_rate(struct cdns_torrent_phy *cdns_phy, else if (cdns_phy->ref_clk_rate == CLK_25_MHZ) /* PMA common configuration 25MHz */ cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, dp->link_rate, dp->ssc); + else if (cdns_phy->ref_clk_rate == CLK_100_MHZ) + /* PMA common configuration 100MHz */ + cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy, dp->link_rate, dp->ssc); + cdns_torrent_dp_pma_cmn_rate(cdns_phy, dp->link_rate, dp->lanes); /* Enable the cmn_pll0_en. */ @@ -1395,6 +1483,7 @@ static int cdns_torrent_dp_init(struct phy *phy) switch (cdns_phy->ref_clk_rate) { case CLK_19_2_MHZ: case CLK_25_MHZ: + case CLK_100_MHZ: /* Valid Ref Clock Rate */ break; default: @@ -1431,6 +1520,11 @@ static int cdns_torrent_dp_init(struct phy *phy) cdns_torrent_dp_pma_cmn_vco_cfg_25mhz(cdns_phy, cdns_phy->max_bit_rate, false); + else if (cdns_phy->ref_clk_rate == CLK_100_MHZ) + cdns_torrent_dp_pma_cmn_vco_cfg_100mhz(cdns_phy, + cdns_phy->max_bit_rate, + false); + cdns_torrent_dp_pma_cmn_rate(cdns_phy, cdns_phy->max_bit_rate, inst->num_lanes); @@ -2511,6 +2605,44 @@ static struct cdns_torrent_vals sl_dp_25_no_ssc_rx_ln_vals = { .num_regs = ARRAY_SIZE(sl_dp_25_no_ssc_rx_ln_regs), }; +/* Single DP, 100 MHz Ref clk, no SSC */ +static struct cdns_reg_pairs sl_dp_100_no_ssc_cmn_regs[] = { + {0x0003, CMN_PLL0_VCOCAL_TCTRL}, + {0x0003, CMN_PLL1_VCOCAL_TCTRL} +}; + +static struct cdns_reg_pairs sl_dp_100_no_ssc_tx_ln_regs[] = { + {0x00FB, TX_PSC_A0}, + {0x04AA, TX_PSC_A2}, + {0x04AA, TX_PSC_A3}, + {0x000F, XCVR_DIAG_BIDI_CTRL} +}; + +static struct cdns_reg_pairs sl_dp_100_no_ssc_rx_ln_regs[] = { + {0x0000, RX_PSC_A0}, + {0x0000, RX_PSC_A2}, + {0x0000, RX_PSC_A3}, + {0x0000, RX_PSC_CAL}, + {0x0000, RX_REE_GCSM1_CTRL}, + {0x0000, RX_REE_GCSM2_CTRL}, + {0x0000, RX_REE_PERGCSM_CTRL} +}; + +static struct cdns_torrent_vals sl_dp_100_no_ssc_cmn_vals = { + .reg_pairs = sl_dp_100_no_ssc_cmn_regs, + .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_cmn_regs), +}; + +static struct cdns_torrent_vals sl_dp_100_no_ssc_tx_ln_vals = { + .reg_pairs = sl_dp_100_no_ssc_tx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_tx_ln_regs), +}; + +static struct cdns_torrent_vals sl_dp_100_no_ssc_rx_ln_vals = { + .reg_pairs = sl_dp_100_no_ssc_rx_ln_regs, + .num_regs = ARRAY_SIZE(sl_dp_100_no_ssc_rx_ln_regs), +}; + /* USB and SGMII/QSGMII link configuration */ static struct cdns_reg_pairs usb_sgmii_link_cmn_regs[] = { {0x0002, PHY_PLL_CFG}, @@ -3450,6 +3582,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3542,6 +3679,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -3634,6 +3776,11 @@ static const struct cdns_torrent_data cdns_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, @@ -3917,6 +4064,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_cmn_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -4009,6 +4161,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_tx_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = NULL, @@ -4101,6 +4258,11 @@ static const struct cdns_torrent_data ti_j721e_map_torrent = { }, }, [CLK_100_MHZ] = { + [TYPE_DP] = { + [TYPE_NONE] = { + [NO_SSC] = &sl_dp_100_no_ssc_rx_ln_vals, + }, + }, [TYPE_PCIE] = { [TYPE_NONE] = { [NO_SSC] = &pcie_100_no_ssc_rx_ln_vals, -- cgit v1.2.3 From 8f3ced2fd4906523e251f252dee03f6c22129e08 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:52 +0200 Subject: phy: cadence-torrent: Add separate functions for reusable code Torrent PHY driver currently supports single link DP configuration. Prepare driver to support multilink DP configurations by adding separate functions for common initialization sequence. Signed-off-by: Swapnil Jakhade Reviewed-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20210728145454.15945-8-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 53 ++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 69466481af26..e4dd8d1711a6 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -1472,24 +1472,11 @@ static int cdns_torrent_phy_off(struct phy *phy) return reset_control_assert(inst->lnk_rst); } -static int cdns_torrent_dp_init(struct phy *phy) +static void cdns_torrent_dp_common_init(struct cdns_torrent_phy *cdns_phy, + struct cdns_torrent_inst *inst) { - unsigned char lane_bits; - int ret; - struct cdns_torrent_inst *inst = phy_get_drvdata(phy); - struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); struct regmap *regmap = cdns_phy->regmap_dptx_phy_reg; - - switch (cdns_phy->ref_clk_rate) { - case CLK_19_2_MHZ: - case CLK_25_MHZ: - case CLK_100_MHZ: - /* Valid Ref Clock Rate */ - break; - default: - dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); - return -EINVAL; - } + unsigned char lane_bits; cdns_torrent_dp_write(regmap, PHY_AUX_CTRL, 0x0003); /* enable AUX */ @@ -1510,8 +1497,10 @@ static int cdns_torrent_dp_init(struct phy *phy) /* release pma_xcvr_pllclk_en_ln_*, only for the master lane */ cdns_torrent_dp_write(regmap, PHY_PMA_XCVR_PLLCLK_EN, 0x0001); - /* PHY PMA registers configuration functions */ - /* Initialize PHY with max supported link rate, without SSC. */ + /* + * PHY PMA registers configuration functions + * Initialize PHY with max supported link rate, without SSC. + */ if (cdns_phy->ref_clk_rate == CLK_19_2_MHZ) cdns_torrent_dp_pma_cmn_vco_cfg_19_2mhz(cdns_phy, cdns_phy->max_bit_rate, @@ -1530,6 +1519,13 @@ static int cdns_torrent_dp_init(struct phy *phy) /* take out of reset */ regmap_field_write(cdns_phy->phy_reset_ctrl, 0x1); +} + +static int cdns_torrent_dp_start(struct cdns_torrent_phy *cdns_phy, + struct cdns_torrent_inst *inst, + struct phy *phy) +{ + int ret; cdns_torrent_phy_on(phy); @@ -1542,6 +1538,27 @@ static int cdns_torrent_dp_init(struct phy *phy) return ret; } +static int cdns_torrent_dp_init(struct phy *phy) +{ + struct cdns_torrent_inst *inst = phy_get_drvdata(phy); + struct cdns_torrent_phy *cdns_phy = dev_get_drvdata(phy->dev.parent); + + switch (cdns_phy->ref_clk_rate) { + case CLK_19_2_MHZ: + case CLK_25_MHZ: + case CLK_100_MHZ: + /* Valid Ref Clock Rate */ + break; + default: + dev_err(cdns_phy->dev, "Unsupported Ref Clock Rate\n"); + return -EINVAL; + } + + cdns_torrent_dp_common_init(cdns_phy, inst); + + return cdns_torrent_dp_start(cdns_phy, inst, phy); +} + static int cdns_torrent_derived_refclk_enable(struct clk_hw *hw) { struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); -- cgit v1.2.3 From 84f55df836916be2b052a5000cca8d7d9fcf2520 Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:53 +0200 Subject: phy: cadence-torrent: Add debug information for PHY configuration Add debug information in probe regarding PHY configuration parameters like single link or multilink protocol along with number of lanes used for each protocol link. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-9-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 36 +++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index e4dd8d1711a6..4024db052cf9 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -573,6 +573,24 @@ static const struct coefficients vltg_coeff[4][4] = { } }; +static const char *cdns_torrent_get_phy_type(enum cdns_torrent_phy_type phy_type) +{ + switch (phy_type) { + case TYPE_DP: + return "DisplayPort"; + case TYPE_PCIE: + return "PCIe"; + case TYPE_SGMII: + return "SGMII"; + case TYPE_QSGMII: + return "QSGMII"; + case TYPE_USB: + return "USB"; + default: + return "None"; + } +} + /* * Set registers responsible for enabling and configuring SSC, with second and * third register values provided by parameters. @@ -2392,10 +2410,9 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) init_dp_regmap++; } - dev_info(dev, "%d lanes, max bit rate %d.%03d Gbps\n", - cdns_phy->phys[node].num_lanes, - cdns_phy->max_bit_rate / 1000, - cdns_phy->max_bit_rate % 1000); + dev_dbg(dev, "DP max bit rate %d.%03d Gbps\n", + cdns_phy->max_bit_rate / 1000, + cdns_phy->max_bit_rate % 1000); gphy->attrs.bus_width = cdns_phy->phys[node].num_lanes; gphy->attrs.max_link_rate = cdns_phy->max_bit_rate; @@ -2427,6 +2444,17 @@ static int cdns_torrent_phy_probe(struct platform_device *pdev) goto put_lnk_rst; } + if (cdns_phy->nsubnodes > 1) + dev_dbg(dev, "Multi-link: %s (%d lanes) & %s (%d lanes)", + cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type), + cdns_phy->phys[0].num_lanes, + cdns_torrent_get_phy_type(cdns_phy->phys[1].phy_type), + cdns_phy->phys[1].num_lanes); + else + dev_dbg(dev, "Single link: %s (%d lanes)", + cdns_torrent_get_phy_type(cdns_phy->phys[0].phy_type), + cdns_phy->phys[0].num_lanes); + return 0; put_child: -- cgit v1.2.3 From 48ac6085bdfcf568e24c1efd45615ec3d5d3545b Mon Sep 17 00:00:00 2001 From: Swapnil Jakhade Date: Wed, 28 Jul 2021 16:54:54 +0200 Subject: phy: cadence-torrent: Check PIPE mode PHY status to be ready for operation PIPE PHY status is used to communicate the completion of several PHY functions. Check if PHY is ready for operation while configured for PIPE mode during startup. Signed-off-by: Swapnil Jakhade Link: https://lore.kernel.org/r/20210728145454.15945-10-sjakhade@cadence.com Signed-off-by: Vinod Koul --- drivers/phy/cadence/phy-cadence-torrent.c | 60 ++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/phy/cadence/phy-cadence-torrent.c b/drivers/phy/cadence/phy-cadence-torrent.c index 4024db052cf9..415ace64adc5 100644 --- a/drivers/phy/cadence/phy-cadence-torrent.c +++ b/drivers/phy/cadence/phy-cadence-torrent.c @@ -51,6 +51,10 @@ #define TORRENT_PHY_PCS_COMMON_OFFSET(block_offset) \ (0xC000 << (block_offset)) +#define TORRENT_PHY_PCS_LANE_CDB_OFFSET(ln, block_offset, reg_offset) \ + ((0xD000 << (block_offset)) + \ + (((ln) << 8) << (reg_offset))) + #define TORRENT_PHY_PMA_COMMON_OFFSET(block_offset) \ (0xE000 << (block_offset)) @@ -223,6 +227,9 @@ #define PHY_PIPE_USB3_GEN2_POST_CFG0 0x0022U #define PHY_PIPE_USB3_GEN2_POST_CFG1 0x0023U +/* PHY PCS lane registers */ +#define PHY_PCS_ISO_LINK_CTRL 0x000BU + /* PHY PMA common registers */ #define PHY_PMA_CMN_CTRL1 0x0000U #define PHY_PMA_CMN_CTRL2 0x0001U @@ -247,6 +254,9 @@ static const struct reg_field phy_pma_pll_raw_ctrl = static const struct reg_field phy_reset_ctrl = REG_FIELD(PHY_RESET, 8, 8); +static const struct reg_field phy_pcs_iso_link_ctrl_1 = + REG_FIELD(PHY_PCS_ISO_LINK_CTRL, 1, 1); + static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0); #define REFCLK_OUT_NUM_CMN_CONFIG 5 @@ -315,12 +325,14 @@ struct cdns_torrent_phy { struct regmap *regmap_phy_pma_common_cdb; struct regmap *regmap_tx_lane_cdb[MAX_NUM_LANES]; struct regmap *regmap_rx_lane_cdb[MAX_NUM_LANES]; + struct regmap *regmap_phy_pcs_lane_cdb[MAX_NUM_LANES]; struct regmap *regmap_dptx_phy_reg; struct regmap_field *phy_pll_cfg; struct regmap_field *phy_pma_cmn_ctrl_1; struct regmap_field *phy_pma_cmn_ctrl_2; struct regmap_field *phy_pma_pll_raw_ctrl; struct regmap_field *phy_reset_ctrl; + struct regmap_field *phy_pcs_iso_link_ctrl_1[MAX_NUM_LANES]; struct clk *clks[CDNS_TORRENT_REFCLK_DRIVER + 1]; struct clk_onecell_data clk_data; }; @@ -455,6 +467,22 @@ static const struct regmap_config cdns_torrent_common_cdb_config = { .reg_read = cdns_regmap_read, }; +#define TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF(n) \ +{ \ + .name = "torrent_phy_pcs_lane" n "_cdb", \ + .reg_stride = 1, \ + .fast_io = true, \ + .reg_write = cdns_regmap_write, \ + .reg_read = cdns_regmap_read, \ +} + +static const struct regmap_config cdns_torrent_phy_pcs_lane_cdb_config[] = { + TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("0"), + TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("1"), + TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("2"), + TORRENT_PHY_PCS_LANE_CDB_REGMAP_CONF("3"), +}; + static const struct regmap_config cdns_torrent_phy_pcs_cmn_cdb_config = { .name = "torrent_phy_pcs_cmn_cdb", .reg_stride = 1, @@ -1469,7 +1497,15 @@ static int cdns_torrent_phy_on(struct phy *phy) return ret; } - mdelay(10); + if (inst->phy_type == TYPE_PCIE || inst->phy_type == TYPE_USB) { + ret = regmap_field_read_poll_timeout(cdns_phy->phy_pcs_iso_link_ctrl_1[inst->mlane], + read_val, !read_val, 1000, + PLL_LOCK_TIMEOUT); + if (ret == -ETIMEDOUT) { + dev_err(cdns_phy->dev, "Timeout waiting for PHY status ready\n"); + return ret; + } + } return 0; } @@ -1719,6 +1755,7 @@ static int cdns_torrent_regfield_init(struct cdns_torrent_phy *cdns_phy) struct device *dev = cdns_phy->dev; struct regmap_field *field; struct regmap *regmap; + int i; regmap = cdns_phy->regmap_phy_pcs_common_cdb; field = devm_regmap_field_alloc(dev, regmap, phy_pll_cfg); @@ -1752,6 +1789,16 @@ static int cdns_torrent_regfield_init(struct cdns_torrent_phy *cdns_phy) } cdns_phy->phy_pma_pll_raw_ctrl = field; + for (i = 0; i < MAX_NUM_LANES; i++) { + regmap = cdns_phy->regmap_phy_pcs_lane_cdb[i]; + field = devm_regmap_field_alloc(dev, regmap, phy_pcs_iso_link_ctrl_1); + if (IS_ERR(field)) { + dev_err(dev, "PHY_PCS_ISO_LINK_CTRL reg field init for ln %d failed\n", i); + return PTR_ERR(field); + } + cdns_phy->phy_pcs_iso_link_ctrl_1[i] = field; + } + return 0; } @@ -1812,6 +1859,17 @@ static int cdns_torrent_regmap_init(struct cdns_torrent_phy *cdns_phy) return PTR_ERR(regmap); } cdns_phy->regmap_rx_lane_cdb[i] = regmap; + + block_offset = TORRENT_PHY_PCS_LANE_CDB_OFFSET(i, block_offset_shift, + reg_offset_shift); + regmap = cdns_regmap_init(dev, sd_base, block_offset, + reg_offset_shift, + &cdns_torrent_phy_pcs_lane_cdb_config[i]); + if (IS_ERR(regmap)) { + dev_err(dev, "Failed to init PHY PCS lane CDB regmap\n"); + return PTR_ERR(regmap); + } + cdns_phy->regmap_phy_pcs_lane_cdb[i] = regmap; } block_offset = TORRENT_COMMON_CDB_OFFSET; -- cgit v1.2.3 From c01608b3b46bfd5285117ab2c66df7cd59b7c67d Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:39 +0800 Subject: dt-bindings: phy: mediatek: tphy: support type switch by pericfg Add support type switch by pericfg register between USB3, PCIe, SATA, SGMII, this is used to replace the way through efuse or jumper. Reviewed-by: Rob Herring Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-1-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/mediatek,tphy.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml index 838852cb8527..9e6c0f43f1c6 100644 --- a/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml +++ b/Documentation/devicetree/bindings/phy/mediatek,tphy.yaml @@ -201,6 +201,22 @@ patternProperties: Specify the flag to enable BC1.2 if support it type: boolean + mediatek,syscon-type: + $ref: /schemas/types.yaml#/definitions/phandle-array + maxItems: 1 + description: + A phandle to syscon used to access the register of type switch, + the field should always be 3 cells long. + items: + items: + - description: + The first cell represents a phandle to syscon + - description: + The second cell represents the register offset + - description: + The third cell represents the index of config segment + enum: [0, 1, 2, 3] + required: - reg - "#phy-cells" -- cgit v1.2.3 From 3fd6611242b9f4e218175c11c8233ac4ab9402e6 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:40 +0800 Subject: phy: phy-mtk-tphy: use clock bulk to get clocks Use clock bulk helpers to get/enable/disable clocks Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-2-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 43 +++++++++++-------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 33000b38fd1b..3259210f08a1 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -280,6 +280,8 @@ #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) #define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) +#define TPHY_CLKS_CNT 2 + enum mtk_phy_version { MTK_PHY_V1 = 1, MTK_PHY_V2, @@ -318,8 +320,7 @@ struct mtk_phy_instance { struct u2phy_banks u2_banks; struct u3phy_banks u3_banks; }; - struct clk *ref_clk; /* reference clock of (digital) phy */ - struct clk *da_ref_clk; /* reference clock of analog phy */ + struct clk_bulk_data clks[TPHY_CLKS_CNT]; u32 index; u8 type; int eye_src; @@ -974,18 +975,9 @@ static int mtk_phy_init(struct phy *phy) struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent); int ret; - ret = clk_prepare_enable(instance->ref_clk); - if (ret) { - dev_err(tphy->dev, "failed to enable ref_clk\n"); + ret = clk_bulk_prepare_enable(TPHY_CLKS_CNT, instance->clks); + if (ret) return ret; - } - - ret = clk_prepare_enable(instance->da_ref_clk); - if (ret) { - dev_err(tphy->dev, "failed to enable da_ref\n"); - clk_disable_unprepare(instance->ref_clk); - return ret; - } switch (instance->type) { case PHY_TYPE_USB2: @@ -1003,8 +995,7 @@ static int mtk_phy_init(struct phy *phy) break; default: dev_err(tphy->dev, "incompatible PHY type\n"); - clk_disable_unprepare(instance->ref_clk); - clk_disable_unprepare(instance->da_ref_clk); + clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks); return -EINVAL; } @@ -1047,8 +1038,7 @@ static int mtk_phy_exit(struct phy *phy) if (instance->type == PHY_TYPE_USB2) u2_phy_instance_exit(tphy, instance); - clk_disable_unprepare(instance->ref_clk); - clk_disable_unprepare(instance->da_ref_clk); + clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks); return 0; } @@ -1211,6 +1201,7 @@ static int mtk_tphy_probe(struct platform_device *pdev) port = 0; for_each_child_of_node(np, child_np) { struct mtk_phy_instance *instance; + struct clk_bulk_data *clks; struct phy *phy; instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); @@ -1247,20 +1238,12 @@ static int mtk_tphy_probe(struct platform_device *pdev) phy_set_drvdata(phy, instance); port++; - instance->ref_clk = devm_clk_get_optional(&phy->dev, "ref"); - if (IS_ERR(instance->ref_clk)) { - dev_err(dev, "failed to get ref_clk(id-%d)\n", port); - retval = PTR_ERR(instance->ref_clk); + clks = instance->clks; + clks[0].id = "ref"; /* digital (& analog) clock */ + clks[1].id = "da_ref"; /* analog clock */ + retval = devm_clk_bulk_get_optional(&phy->dev, TPHY_CLKS_CNT, clks); + if (retval) goto put_child; - } - - instance->da_ref_clk = - devm_clk_get_optional(&phy->dev, "da_ref"); - if (IS_ERR(instance->da_ref_clk)) { - dev_err(dev, "failed to get da_ref_clk(id-%d)\n", port); - retval = PTR_ERR(instance->da_ref_clk); - goto put_child; - } } provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); -- cgit v1.2.3 From 39099a4433586cdf30a7fc73aae4c77159b4a8c7 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:41 +0800 Subject: phy: phy-mtk-tphy: support type switch by pericfg Add support type switch between USB3, PCIe, SATA and SGMII by pericfg register, this is used to take the place of efuse or jumper. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-3-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 84 ++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 3259210f08a1..a6502058a1a5 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include #include #include +#include /* version V1 sub-banks offset base address */ /* banks shared by multiple phys */ @@ -280,6 +282,14 @@ #define RG_CDR_BIRLTD0_GEN3_MSK GENMASK(4, 0) #define RG_CDR_BIRLTD0_GEN3_VAL(x) (0x1f & (x)) +/* PHY switch between pcie/usb3/sgmii/sata */ +#define USB_PHY_SWITCH_CTRL 0x0 +#define RG_PHY_SW_TYPE GENMASK(3, 0) +#define RG_PHY_SW_PCIE 0x0 +#define RG_PHY_SW_USB3 0x1 +#define RG_PHY_SW_SGMII 0x2 +#define RG_PHY_SW_SATA 0x3 + #define TPHY_CLKS_CNT 2 enum mtk_phy_version { @@ -322,7 +332,10 @@ struct mtk_phy_instance { }; struct clk_bulk_data clks[TPHY_CLKS_CNT]; u32 index; - u8 type; + u32 type; + struct regmap *type_sw; + u32 type_sw_reg; + u32 type_sw_index; int eye_src; int eye_vrt; int eye_term; @@ -969,6 +982,64 @@ static void u2_phy_props_set(struct mtk_tphy *tphy, } } +/* type switch for usb3/pcie/sgmii/sata */ +static int phy_type_syscon_get(struct mtk_phy_instance *instance, + struct device_node *dn) +{ + struct of_phandle_args args; + int ret; + + /* type switch function is optional */ + if (!of_property_read_bool(dn, "mediatek,syscon-type")) + return 0; + + ret = of_parse_phandle_with_fixed_args(dn, "mediatek,syscon-type", + 2, 0, &args); + if (ret) + return ret; + + instance->type_sw_reg = args.args[0]; + instance->type_sw_index = args.args[1] & 0x3; /* <=3 */ + instance->type_sw = syscon_node_to_regmap(args.np); + of_node_put(args.np); + dev_info(&instance->phy->dev, "type_sw - reg %#x, index %d\n", + instance->type_sw_reg, instance->type_sw_index); + + return PTR_ERR_OR_ZERO(instance->type_sw); +} + +static int phy_type_set(struct mtk_phy_instance *instance) +{ + int type; + u32 mask; + + if (!instance->type_sw) + return 0; + + switch (instance->type) { + case PHY_TYPE_USB3: + type = RG_PHY_SW_USB3; + break; + case PHY_TYPE_PCIE: + type = RG_PHY_SW_PCIE; + break; + case PHY_TYPE_SGMII: + type = RG_PHY_SW_SGMII; + break; + case PHY_TYPE_SATA: + type = RG_PHY_SW_SATA; + break; + case PHY_TYPE_USB2: + default: + return 0; + } + + mask = RG_PHY_SW_TYPE << (instance->type_sw_index * BITS_PER_BYTE); + regmap_update_bits(instance->type_sw, instance->type_sw_reg, mask, type); + + return 0; +} + static int mtk_phy_init(struct phy *phy) { struct mtk_phy_instance *instance = phy_get_drvdata(phy); @@ -993,6 +1064,9 @@ static int mtk_phy_init(struct phy *phy) case PHY_TYPE_SATA: sata_phy_instance_init(tphy, instance); break; + case PHY_TYPE_SGMII: + /* nothing to do, only used to set type */ + break; default: dev_err(tphy->dev, "incompatible PHY type\n"); clk_bulk_disable_unprepare(TPHY_CLKS_CNT, instance->clks); @@ -1081,7 +1155,8 @@ static struct phy *mtk_phy_xlate(struct device *dev, if (!(instance->type == PHY_TYPE_USB2 || instance->type == PHY_TYPE_USB3 || instance->type == PHY_TYPE_PCIE || - instance->type == PHY_TYPE_SATA)) { + instance->type == PHY_TYPE_SATA || + instance->type == PHY_TYPE_SGMII)) { dev_err(dev, "unsupported device type: %d\n", instance->type); return ERR_PTR(-EINVAL); } @@ -1100,6 +1175,7 @@ static struct phy *mtk_phy_xlate(struct device *dev, } phy_parse_property(tphy, instance); + phy_type_set(instance); return instance->phy; } @@ -1244,6 +1320,10 @@ static int mtk_tphy_probe(struct platform_device *pdev) retval = devm_clk_bulk_get_optional(&phy->dev, TPHY_CLKS_CNT, clks); if (retval) goto put_child; + + retval = phy_type_syscon_get(instance, child_np); + if (retval) + goto put_child; } provider = devm_of_phy_provider_register(dev, mtk_phy_xlate); -- cgit v1.2.3 From 926b83e5f9f0427f588b6c1e2b3b077979c39d3e Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:42 +0800 Subject: phy: phy-mtk-tphy: print error log using child device Print error log using child devices instead of parent device. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-4-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index a6502058a1a5..9d4b34298137 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -1278,6 +1278,7 @@ static int mtk_tphy_probe(struct platform_device *pdev) for_each_child_of_node(np, child_np) { struct mtk_phy_instance *instance; struct clk_bulk_data *clks; + struct device *subdev; struct phy *phy; instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); @@ -1295,16 +1296,17 @@ static int mtk_tphy_probe(struct platform_device *pdev) goto put_child; } + subdev = &phy->dev; retval = of_address_to_resource(child_np, 0, &res); if (retval) { - dev_err(dev, "failed to get address resource(id-%d)\n", + dev_err(subdev, "failed to get address resource(id-%d)\n", port); goto put_child; } - instance->port_base = devm_ioremap_resource(&phy->dev, &res); + instance->port_base = devm_ioremap_resource(subdev, &res); if (IS_ERR(instance->port_base)) { - dev_err(dev, "failed to remap phy regs\n"); + dev_err(subdev, "failed to remap phy regs\n"); retval = PTR_ERR(instance->port_base); goto put_child; } @@ -1317,7 +1319,7 @@ static int mtk_tphy_probe(struct platform_device *pdev) clks = instance->clks; clks[0].id = "ref"; /* digital (& analog) clock */ clks[1].id = "da_ref"; /* analog clock */ - retval = devm_clk_bulk_get_optional(&phy->dev, TPHY_CLKS_CNT, clks); + retval = devm_clk_bulk_get_optional(subdev, TPHY_CLKS_CNT, clks); if (retval) goto put_child; -- cgit v1.2.3 From 1c6de3fc53ca14d3266d219e2ee62b8e5b1e2a6f Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:43 +0800 Subject: phy: phy-mtk-tphy: remove error log of ioremap failure devm_ioremap_resource() will print log if error happens. Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-5-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-tphy.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 9d4b34298137..cdcef865fe9e 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -1306,7 +1306,6 @@ static int mtk_tphy_probe(struct platform_device *pdev) instance->port_base = devm_ioremap_resource(subdev, &res); if (IS_ERR(instance->port_base)) { - dev_err(subdev, "failed to remap phy regs\n"); retval = PTR_ERR(instance->port_base); goto put_child; } -- cgit v1.2.3 From 5f71b1e4f719e3c2312f20a76ee039ae209e72da Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:44 +0800 Subject: phy: phy-mtk-ufs: use clock bulk to get clocks Use clock bulk helpers to get/enable/disable clocks Reviewed-by: Stanley Chu Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-6-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-ufs.c | 44 ++++++++++---------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c index 769b00b038d8..a6af06941203 100644 --- a/drivers/phy/mediatek/phy-mtk-ufs.c +++ b/drivers/phy/mediatek/phy-mtk-ufs.c @@ -31,11 +31,12 @@ #define FRC_CDR_ISO_EN BIT(19) #define CDR_ISO_EN BIT(20) +#define UFSPHY_CLKS_CNT 2 + struct ufs_mtk_phy { struct device *dev; void __iomem *mmio; - struct clk *mp_clk; - struct clk *unipro_clk; + struct clk_bulk_data clks[UFSPHY_CLKS_CNT]; }; static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) @@ -74,20 +75,11 @@ static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) { struct device *dev = phy->dev; + struct clk_bulk_data *clks = phy->clks; - phy->unipro_clk = devm_clk_get(dev, "unipro"); - if (IS_ERR(phy->unipro_clk)) { - dev_err(dev, "failed to get clock: unipro"); - return PTR_ERR(phy->unipro_clk); - } - - phy->mp_clk = devm_clk_get(dev, "mp"); - if (IS_ERR(phy->mp_clk)) { - dev_err(dev, "failed to get clock: mp"); - return PTR_ERR(phy->mp_clk); - } - - return 0; + clks[0].id = "unipro"; + clks[1].id = "mp"; + return devm_clk_bulk_get(dev, UFSPHY_CLKS_CNT, clks); } static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) @@ -150,26 +142,13 @@ static int ufs_mtk_phy_power_on(struct phy *generic_phy) struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); int ret; - ret = clk_prepare_enable(phy->unipro_clk); - if (ret) { - dev_err(phy->dev, "unipro_clk enable failed %d\n", ret); - goto out; - } - - ret = clk_prepare_enable(phy->mp_clk); - if (ret) { - dev_err(phy->dev, "mp_clk enable failed %d\n", ret); - goto out_unprepare_unipro_clk; - } + ret = clk_bulk_prepare_enable(UFSPHY_CLKS_CNT, phy->clks); + if (ret) + return ret; ufs_mtk_phy_set_active(phy); return 0; - -out_unprepare_unipro_clk: - clk_disable_unprepare(phy->unipro_clk); -out: - return ret; } static int ufs_mtk_phy_power_off(struct phy *generic_phy) @@ -178,8 +157,7 @@ static int ufs_mtk_phy_power_off(struct phy *generic_phy) ufs_mtk_phy_set_deep_hibern(phy); - clk_disable_unprepare(phy->unipro_clk); - clk_disable_unprepare(phy->mp_clk); + clk_bulk_disable_unprepare(UFSPHY_CLKS_CNT, phy->clks); return 0; } -- cgit v1.2.3 From 9474458753880e63c2b31fec3753316fa5c8e20d Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:45 +0800 Subject: phy: phy-mtk-hdmi: convert to devm_platform_ioremap_resource Use devm_platform_ioremap_resource to simplify code Acked-by: Chun-Kuang Hu Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-7-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-hdmi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-hdmi.c b/drivers/phy/mediatek/phy-mtk-hdmi.c index 8ad8f717ef43..5fb4217fb8e0 100644 --- a/drivers/phy/mediatek/phy-mtk-hdmi.c +++ b/drivers/phy/mediatek/phy-mtk-hdmi.c @@ -100,7 +100,6 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_hdmi_phy *hdmi_phy; - struct resource *mem; struct clk *ref_clk; const char *ref_clk_name; struct clk_init_data clk_init = { @@ -116,11 +115,9 @@ static int mtk_hdmi_phy_probe(struct platform_device *pdev) if (!hdmi_phy) return -ENOMEM; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdmi_phy->regs = devm_ioremap_resource(dev, mem); - if (IS_ERR(hdmi_phy->regs)) { + hdmi_phy->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(hdmi_phy->regs)) return PTR_ERR(hdmi_phy->regs); - } ref_clk = devm_clk_get(dev, "pll_ref"); if (IS_ERR(ref_clk)) { -- cgit v1.2.3 From 75203e7994feedc52c62eb42f6b7a7087145813b Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:46 +0800 Subject: phy: phy-mtk-mipi-dsi: remove dummy assignment of error number Return the error number directly without assignment Acked-by: Chun-Kuang Hu Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-8-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 01cf31633019..61c942fbf4a1 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -203,10 +203,8 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) phy_set_drvdata(phy, mipi_tx); phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) { - ret = PTR_ERR(phy_provider); - return ret; - } + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); mipi_tx->dev = dev; -- cgit v1.2.3 From 7508d1e4031168afac1793bf1f2a29a7c3fce423 Mon Sep 17 00:00:00 2001 From: Chunfeng Yun Date: Tue, 17 Aug 2021 17:19:47 +0800 Subject: phy: phy-mtk-mipi-dsi: convert to devm_platform_ioremap_resource Use devm_platform_ioremap_resource to simplify code Acked-by: Chun-Kuang Hu Signed-off-by: Chunfeng Yun Link: https://lore.kernel.org/r/1629191987-20774-9-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Vinod Koul --- drivers/phy/mediatek/phy-mtk-mipi-dsi.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c index 61c942fbf4a1..28ad9403c441 100644 --- a/drivers/phy/mediatek/phy-mtk-mipi-dsi.c +++ b/drivers/phy/mediatek/phy-mtk-mipi-dsi.c @@ -130,7 +130,6 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_mipi_tx *mipi_tx; - struct resource *mem; const char *ref_clk_name; struct clk *ref_clk; struct clk_init_data clk_init = { @@ -148,11 +147,9 @@ static int mtk_mipi_tx_probe(struct platform_device *pdev) mipi_tx->driver_data = of_device_get_match_data(dev); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mipi_tx->regs = devm_ioremap_resource(dev, mem); - if (IS_ERR(mipi_tx->regs)) { + mipi_tx->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mipi_tx->regs)) return PTR_ERR(mipi_tx->regs); - } ref_clk = devm_clk_get(dev, NULL); if (IS_ERR(ref_clk)) { -- cgit v1.2.3 From e1f31c93a8d292f2e5b17daa384feaa28453f25e Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Tue, 17 Aug 2021 09:45:39 +0530 Subject: phy: amlogic: meson8b-usb2: Power off the PHY by putting it into reset mode Power off the PHY by putting it into reset mode. Cc: Martin Blumenstingl Acked-by: Martin Blumenstingl Signed-off-by: Anand Moon Link: https://lore.kernel.org/r/20210817041548.1276-6-linux.amoon@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/amlogic/phy-meson8b-usb2.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c index 03c061dd5f0d..2aad45c55494 100644 --- a/drivers/phy/amlogic/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -219,6 +219,10 @@ static int phy_meson8b_usb2_power_off(struct phy *phy) clk_disable_unprepare(priv->clk_usb); clk_disable_unprepare(priv->clk_usb_general); + /* power off the PHY by putting it into reset mode */ + regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET, + REG_CTRL_POWER_ON_RESET); + return 0; } -- cgit v1.2.3 From c7c4024348994208ac3bf85daf1a6195b7c5f7d3 Mon Sep 17 00:00:00 2001 From: Anand Moon Date: Tue, 17 Aug 2021 09:45:40 +0530 Subject: phy: amlogic: meson8b-usb2: don't log an error on -EPROBE_DEFER devm_phy_create can return -EPROBE_DEFER if the vbus-supply is not ready yet. Silence this warning as the driver framework will re-attempt registering the PHY. Use dev_err_probe() for phy resources to indicate the deferral reason when waiting for the resource to come up. Cc: Martin Blumenstingl Reviewed-by: Martin Blumenstingl Signed-off-by: Anand Moon Link: https://lore.kernel.org/r/20210817041548.1276-7-linux.amoon@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/amlogic/phy-meson8b-usb2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/phy/amlogic/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c index 2aad45c55494..cf10bed40528 100644 --- a/drivers/phy/amlogic/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -277,8 +277,8 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev) phy = devm_phy_create(&pdev->dev, NULL, &phy_meson8b_usb2_ops); if (IS_ERR(phy)) { - dev_err(&pdev->dev, "failed to create PHY\n"); - return PTR_ERR(phy); + return dev_err_probe(&pdev->dev, PTR_ERR(phy), + "failed to create PHY\n"); } phy_set_drvdata(phy, priv); -- cgit v1.2.3 From 89161cd00838ac25f401e3d149171908148af7be Mon Sep 17 00:00:00 2001 From: Piyush Mehta Date: Wed, 18 Aug 2021 14:13:11 +0530 Subject: phy: xilinx: zynqmp: skip PHY initialization and PLL lock for USB PHY initialization for USB is required on linux boot or when gt lane is changed from the current one and it is applicable on PLL lock too. Signed-off-by: Piyush Mehta Link: https://lore.kernel.org/r/20210818084311.2643986-1-piyush.mehta@xilinx.com Signed-off-by: Vinod Koul --- drivers/phy/xilinx/phy-zynqmp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/phy/xilinx/phy-zynqmp.c b/drivers/phy/xilinx/phy-zynqmp.c index 35652152ce5d..f478d8a17115 100644 --- a/drivers/phy/xilinx/phy-zynqmp.c +++ b/drivers/phy/xilinx/phy-zynqmp.c @@ -626,6 +626,9 @@ static int xpsgtr_phy_power_on(struct phy *phy) struct xpsgtr_phy *gtr_phy = phy_get_drvdata(phy); int ret = 0; + /* Skip initialization if not required. */ + if (!xpsgtr_phy_init_required(gtr_phy)) + return ret; /* * Wait for the PLL to lock. For DP, only wait on DP0 to avoid * cumulating waits for both lanes. The user is expected to initialize -- cgit v1.2.3 From 09cbd1df7d2615c19e40facbe31fdcb5f1ebfa96 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 6 Aug 2021 08:46:11 +0200 Subject: firmware: raspberrypi: Fix a leak in 'rpi_firmware_get()' The reference taken by 'of_find_device_by_node()' must be released when not needed anymore. Add the corresponding 'put_device()' in the normal and error handling paths. Fixes: 4e3d60656a72 ("ARM: bcm2835: Add the Raspberry Pi firmware driver") Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/5e17e5409b934cd08bf6f9279c73be5c1cb11cce.1628232242.git.christophe.jaillet@wanadoo.fr Signed-off-by: Greg Kroah-Hartman --- drivers/firmware/raspberrypi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 250e01680742..4b8978b254f9 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -329,12 +329,18 @@ struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node) fw = platform_get_drvdata(pdev); if (!fw) - return NULL; + goto err_put_device; if (!kref_get_unless_zero(&fw->consumers)) - return NULL; + goto err_put_device; + + put_device(&pdev->dev); return fw; + +err_put_device: + put_device(&pdev->dev); + return NULL; } EXPORT_SYMBOL_GPL(rpi_firmware_get); -- cgit v1.2.3 From c75be56e35b2eef824a2ac8d90a98f9e65b28efa Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 Aug 2021 10:48:52 -0700 Subject: lkdtm/bugs: Add ARRAY_BOUNDS to selftests Add CONFIG hints about why the ARRAY_BOUNDS test might fail, and similarly include the CONFIGs needed to pass the ARRAY_BOUNDS test via the selftests, and add to selftests. Cc: kernelci@groups.io Suggested-by: Guillaume Tucker Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210818174855.2307828-2-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/bugs.c | 1 + tools/testing/selftests/lkdtm/config | 2 ++ tools/testing/selftests/lkdtm/tests.txt | 1 + 3 files changed, 4 insertions(+) diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 88c218a9f8b3..03171e412356 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -267,6 +267,7 @@ void lkdtm_ARRAY_BOUNDS(void) kfree(not_checked); kfree(checked); pr_err("FAIL: survived array bounds overflow!\n"); + pr_expected_config(CONFIG_UBSAN_BOUNDS); } void lkdtm_CORRUPT_LIST_ADD(void) diff --git a/tools/testing/selftests/lkdtm/config b/tools/testing/selftests/lkdtm/config index 013446e87f1f..38edea25631b 100644 --- a/tools/testing/selftests/lkdtm/config +++ b/tools/testing/selftests/lkdtm/config @@ -6,3 +6,5 @@ CONFIG_HARDENED_USERCOPY=y # CONFIG_HARDENED_USERCOPY_FALLBACK is not set CONFIG_RANDOMIZE_KSTACK_OFFSET_DEFAULT=y CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y +CONFIG_UBSAN_BOUNDS=y +CONFIG_UBSAN_TRAP=y diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 846cfd508d3c..6a33dbea8491 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -7,6 +7,7 @@ EXCEPTION #EXHAUST_STACK Corrupts memory on failure #CORRUPT_STACK Crashes entire system on success #CORRUPT_STACK_STRONG Crashes entire system on success +ARRAY_BOUNDS CORRUPT_LIST_ADD list_add corruption CORRUPT_LIST_DEL list_del corruption STACK_GUARD_PAGE_LEADING -- cgit v1.2.3 From fe8e353bfda6d6c8cefd0a933640025ad3d302e5 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 Aug 2021 10:48:53 -0700 Subject: lkdtm/fortify: Consolidate FORTIFY_SOURCE tests The FORTIFY_SOURCE tests were split between bugs.c and fortify.c. Move tests into fortify.c, standardize their naming, add CONFIG hints, and add them to the lkdtm selftests. Cc: Arnd Bergmann Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210818174855.2307828-3-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/bugs.c | 50 ------------------------------- drivers/misc/lkdtm/core.c | 4 +-- drivers/misc/lkdtm/fortify.c | 53 +++++++++++++++++++++++++++++++++ drivers/misc/lkdtm/lkdtm.h | 4 +-- tools/testing/selftests/lkdtm/tests.txt | 2 ++ 5 files changed, 59 insertions(+), 54 deletions(-) diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c index 03171e412356..4282b625200f 100644 --- a/drivers/misc/lkdtm/bugs.c +++ b/drivers/misc/lkdtm/bugs.c @@ -507,53 +507,3 @@ noinline void lkdtm_CORRUPT_PAC(void) pr_err("XFAIL: this test is arm64-only\n"); #endif } - -void lkdtm_FORTIFY_OBJECT(void) -{ - struct target { - char a[10]; - } target[2] = {}; - int result; - - /* - * Using volatile prevents the compiler from determining the value of - * 'size' at compile time. Without that, we would get a compile error - * rather than a runtime error. - */ - volatile int size = 11; - - pr_info("trying to read past the end of a struct\n"); - - result = memcmp(&target[0], &target[1], size); - - /* Print result to prevent the code from being eliminated */ - pr_err("FAIL: fortify did not catch an object overread!\n" - "\"%d\" was the memcmp result.\n", result); -} - -void lkdtm_FORTIFY_SUBOBJECT(void) -{ - struct target { - char a[10]; - char b[10]; - } target; - char *src; - - src = kmalloc(20, GFP_KERNEL); - strscpy(src, "over ten bytes", 20); - - pr_info("trying to strcpy past the end of a member of a struct\n"); - - /* - * strncpy(target.a, src, 20); will hit a compile error because the - * compiler knows at build time that target.a < 20 bytes. Use strcpy() - * to force a runtime error. - */ - strcpy(target.a, src); - - /* Use target.a to prevent the code from being eliminated */ - pr_err("FAIL: fortify did not catch an sub-object overrun!\n" - "\"%s\" was copied.\n", target.a); - - kfree(src); -} diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index c9a0ad6d5d72..486ce0cfde03 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -118,8 +118,6 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(UNSET_SMEP), CRASHTYPE(CORRUPT_PAC), CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE), - CRASHTYPE(FORTIFY_OBJECT), - CRASHTYPE(FORTIFY_SUBOBJECT), CRASHTYPE(SLAB_LINEAR_OVERFLOW), CRASHTYPE(VMALLOC_LINEAR_OVERFLOW), CRASHTYPE(WRITE_AFTER_FREE), @@ -179,6 +177,8 @@ static const struct crashtype crashtypes[] = { CRASHTYPE(USERCOPY_KERNEL), CRASHTYPE(STACKLEAK_ERASING), CRASHTYPE(CFI_FORWARD_PROTO), + CRASHTYPE(FORTIFIED_OBJECT), + CRASHTYPE(FORTIFIED_SUBOBJECT), CRASHTYPE(FORTIFIED_STRSCPY), CRASHTYPE(DOUBLE_FAULT), #ifdef CONFIG_PPC_BOOK3S_64 diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c index 0f51d31b57ca..d06458a4858e 100644 --- a/drivers/misc/lkdtm/fortify.c +++ b/drivers/misc/lkdtm/fortify.c @@ -8,6 +8,59 @@ #include #include +static volatile int fortify_scratch_space; + +void lkdtm_FORTIFIED_OBJECT(void) +{ + struct target { + char a[10]; + } target[2] = {}; + /* + * Using volatile prevents the compiler from determining the value of + * 'size' at compile time. Without that, we would get a compile error + * rather than a runtime error. + */ + volatile int size = 11; + + pr_info("trying to read past the end of a struct\n"); + + /* Store result to global to prevent the code from being eliminated */ + fortify_scratch_space = memcmp(&target[0], &target[1], size); + + pr_err("FAIL: fortify did not block an object overread!\n"); + pr_expected_config(CONFIG_FORTIFY_SOURCE); +} + +void lkdtm_FORTIFIED_SUBOBJECT(void) +{ + struct target { + char a[10]; + char b[10]; + } target; + volatile int size = 20; + char *src; + + src = kmalloc(size, GFP_KERNEL); + strscpy(src, "over ten bytes", size); + size = strlen(src) + 1; + + pr_info("trying to strcpy past the end of a member of a struct\n"); + + /* + * memcpy(target.a, src, 20); will hit a compile error because the + * compiler knows at build time that target.a < 20 bytes. Use a + * volatile to force a runtime error. + */ + memcpy(target.a, src, size); + + /* Store result to global to prevent the code from being eliminated */ + fortify_scratch_space = target.a[3]; + + pr_err("FAIL: fortify did not block an sub-object overrun!\n"); + pr_expected_config(CONFIG_FORTIFY_SOURCE); + + kfree(src); +} /* * Calls fortified strscpy to test that it returns the same result as vanilla diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index 6a30b60519f3..f2e61581c1ae 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -74,8 +74,6 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void); void lkdtm_UNSET_SMEP(void); void lkdtm_DOUBLE_FAULT(void); void lkdtm_CORRUPT_PAC(void); -void lkdtm_FORTIFY_OBJECT(void); -void lkdtm_FORTIFY_SUBOBJECT(void); /* heap.c */ void __init lkdtm_heap_init(void); @@ -150,6 +148,8 @@ void lkdtm_STACKLEAK_ERASING(void); void lkdtm_CFI_FORWARD_PROTO(void); /* fortify.c */ +void lkdtm_FORTIFIED_OBJECT(void); +void lkdtm_FORTIFIED_SUBOBJECT(void); void lkdtm_FORTIFIED_STRSCPY(void); /* powerpc.c */ diff --git a/tools/testing/selftests/lkdtm/tests.txt b/tools/testing/selftests/lkdtm/tests.txt index 6a33dbea8491..09f7bfa383cc 100644 --- a/tools/testing/selftests/lkdtm/tests.txt +++ b/tools/testing/selftests/lkdtm/tests.txt @@ -73,4 +73,6 @@ USERCOPY_KERNEL STACKLEAK_ERASING OK: the rest of the thread stack is properly erased CFI_FORWARD_PROTO FORTIFIED_STRSCPY +FORTIFIED_OBJECT +FORTIFIED_SUBOBJECT PPC_SLB_MULTIHIT Recovered -- cgit v1.2.3 From b8661450bc7f1f3dd746f8cac48534e0dfdc1cdf Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 Aug 2021 10:48:54 -0700 Subject: lkdtm: Add kernel version to failure hints In an effort to keep as much information in once place as possible in CI logs, report the kernel version and architecture in the failure hints. Cc: Arnd Bergmann Cc: kernelci@groups.io Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210818174855.2307828-4-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/lkdtm.h | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h index f2e61581c1ae..d7d64d9765eb 100644 --- a/drivers/misc/lkdtm/lkdtm.h +++ b/drivers/misc/lkdtm/lkdtm.h @@ -5,13 +5,17 @@ #define pr_fmt(fmt) "lkdtm: " fmt #include +#include +#include + +#define LKDTM_KERNEL "kernel (" UTS_RELEASE " " UTS_MACHINE ")" #define pr_expected_config(kconfig) \ { \ if (IS_ENABLED(kconfig)) \ - pr_err("Unexpected! This kernel was built with " #kconfig "=y\n"); \ + pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y\n"); \ else \ - pr_warn("This is probably expected, since this kernel was built *without* " #kconfig "=y\n"); \ + pr_warn("This is probably expected, since this " LKDTM_KERNEL " was built *without* " #kconfig "=y\n"); \ } #ifndef MODULE @@ -21,24 +25,24 @@ int lkdtm_check_bool_cmdline(const char *param); if (IS_ENABLED(kconfig)) { \ switch (lkdtm_check_bool_cmdline(param)) { \ case 0: \ - pr_warn("This is probably expected, since this kernel was built with " #kconfig "=y but booted with '" param "=N'\n"); \ + pr_warn("This is probably expected, since this " LKDTM_KERNEL " was built with " #kconfig "=y but booted with '" param "=N'\n"); \ break; \ case 1: \ - pr_err("Unexpected! This kernel was built with " #kconfig "=y and booted with '" param "=Y'\n"); \ + pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y and booted with '" param "=Y'\n"); \ break; \ default: \ - pr_err("Unexpected! This kernel was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \ + pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \ } \ } else { \ switch (lkdtm_check_bool_cmdline(param)) { \ case 0: \ - pr_warn("This is probably expected, as kernel was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \ + pr_warn("This is probably expected, as this " LKDTM_KERNEL " was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \ break; \ case 1: \ - pr_err("Unexpected! This kernel was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \ + pr_err("Unexpected! This " LKDTM_KERNEL " was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \ break; \ default: \ - pr_err("This is probably expected, since this kernel was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \ + pr_err("This is probably expected, since this " LKDTM_KERNEL " was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \ break; \ } \ } \ -- cgit v1.2.3 From e6d468d32cd084edd030a8bae76440b17b854b5c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 18 Aug 2021 10:48:55 -0700 Subject: lkdtm/heap: Avoid __alloc_size hint warning for VMALLOC_LINEAR_OVERFLOW Once __alloc_size hints have been added, the compiler will (correctly!) see this as an overflow. We are, however, trying to test for this condition at run-time (not compile-time), so work around it with a volatile int offset. Cc: Arnd Bergmann Signed-off-by: Kees Cook Link: https://lore.kernel.org/r/20210818174855.2307828-5-keescook@chromium.org Signed-off-by: Greg Kroah-Hartman --- drivers/misc/lkdtm/heap.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c index 3d9aae5821a0..8a92f5a800fa 100644 --- a/drivers/misc/lkdtm/heap.c +++ b/drivers/misc/lkdtm/heap.c @@ -12,6 +12,13 @@ static struct kmem_cache *double_free_cache; static struct kmem_cache *a_cache; static struct kmem_cache *b_cache; +/* + * Using volatile here means the compiler cannot ever make assumptions + * about this value. This means compile-time length checks involving + * this variable cannot be performed; only run-time checks. + */ +static volatile int __offset = 1; + /* * If there aren't guard pages, it's likely that a consecutive allocation will * let us overflow into the second allocation without overwriting something real. @@ -24,7 +31,7 @@ void lkdtm_VMALLOC_LINEAR_OVERFLOW(void) two = vzalloc(PAGE_SIZE); pr_info("Attempting vmalloc linear overflow ...\n"); - memset(one, 0xAA, PAGE_SIZE + 1); + memset(one, 0xAA, PAGE_SIZE + __offset); vfree(two); vfree(one); -- cgit v1.2.3 From 85e2414c518a03a21dddd4bc88fec2723c5e1197 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:12 -0600 Subject: coresight: syscfg: Initial coresight system configuration Creates an system management API to allow complex configurations and features to be programmed into a CoreSight infrastructure. A feature is defined as a programming set for a device or class of devices. A configuration is a set of features across the system that are enabled for a trace session. The API will manage system wide configuration, and allow complex programmed features to be added to individual device instances, and provide for system wide configuration selection on trace capture operations. This patch creates the initial data object and the initial API for loading configurations and features. Link: https://lore.kernel.org/r/20210723165444.1048-2-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-2-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-config.h | 142 ++++++++++++++++ drivers/hwtracing/coresight/coresight-core.c | 12 +- drivers/hwtracing/coresight/coresight-etm-perf.c | 2 +- drivers/hwtracing/coresight/coresight-etm-perf.h | 2 +- drivers/hwtracing/coresight/coresight-syscfg.c | 199 +++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-syscfg.h | 46 ++++++ 7 files changed, 401 insertions(+), 4 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.h create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg.h diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index d60816509755..3d037f17aade 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o + coresight-sysfs.o coresight-syscfg.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h new file mode 100644 index 000000000000..21aa7464dcdc --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -0,0 +1,142 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach + */ + +#ifndef _CORESIGHT_CORESIGHT_CONFIG_H +#define _CORESIGHT_CORESIGHT_CONFIG_H + +#include +#include + +/* CoreSight Configuration Management - component and system wide configuration */ + +/* + * Register type flags for register value descriptor: + * describe how the value is interpreted, and handled. + */ +#define CS_CFG_REG_TYPE_STD 0x80 /* reg is standard reg */ +#define CS_CFG_REG_TYPE_RESOURCE 0x40 /* reg is a resource */ +#define CS_CFG_REG_TYPE_VAL_PARAM 0x08 /* reg value uses param */ +#define CS_CFG_REG_TYPE_VAL_MASK 0x04 /* reg value bit masked */ +#define CS_CFG_REG_TYPE_VAL_64BIT 0x02 /* reg value 64 bit */ +#define CS_CFG_REG_TYPE_VAL_SAVE 0x01 /* reg value save on disable */ + +/* + * flags defining what device class a feature will match to when processing a + * system configuration - used by config data and devices. + */ +#define CS_CFG_MATCH_CLASS_SRC_ALL 0x0001 /* match any source */ +#define CS_CFG_MATCH_CLASS_SRC_ETM4 0x0002 /* match any ETMv4 device */ + +/* flags defining device instance matching - used in config match desc data. */ +#define CS_CFG_MATCH_INST_ANY 0x80000000 /* any instance of a class */ + +/* + * Limit number of presets in a configuration + * This is related to the number of bits (4) we use to select the preset on + * the perf command line. Preset 0 is always none selected. + * See PMU_FORMAT_ATTR(preset, "config:0-3") in coresight-etm-perf.c + */ +#define CS_CFG_CONFIG_PRESET_MAX 15 + +/** + * Parameter descriptor for a device feature. + * + * @name: Name of parameter. + * @value: Initial or default value. + */ +struct cscfg_parameter_desc { + const char *name; + u64 value; +}; + +/** + * Representation of register value and a descriptor of register usage. + * + * Used as a descriptor in the feature descriptors. + * Used as a value in when in a feature loading into a csdev. + * + * Supports full 64 bit register value, or 32 bit value with optional mask + * value. + * + * @type: define register usage and interpretation. + * @offset: the address offset for register in the hardware device (per device specification). + * @hw_info: optional hardware device type specific information. (ETM / CTI specific etc) + * @val64: 64 bit value. + * @val32: 32 bit value. + * @mask32: 32 bit mask when using 32 bit value to access device register - if mask type. + * @param_idx: parameter index value into parameter array if param type. + */ +struct cscfg_regval_desc { + struct { + u32 type:8; + u32 offset:12; + u32 hw_info:12; + }; + union { + u64 val64; + struct { + u32 val32; + u32 mask32; + }; + u32 param_idx; + }; +}; + +/** + * Device feature descriptor - combination of registers and parameters to + * program a device to implement a specific complex function. + * + * @name: feature name. + * @description: brief description of the feature. + * @item: List entry. + * @match_flags: matching information if loading into a device + * @nr_params: number of parameters used. + * @params_desc: array of parameters used. + * @nr_regs: number of registers used. + * @regs_desc: array of registers used. + */ +struct cscfg_feature_desc { + const char *name; + const char *description; + struct list_head item; + u32 match_flags; + int nr_params; + struct cscfg_parameter_desc *params_desc; + int nr_regs; + struct cscfg_regval_desc *regs_desc; +}; + +/** + * Configuration descriptor - describes selectable system configuration. + * + * A configuration describes device features in use, and may provide preset + * values for the parameters in those features. + * + * A single set of presets is the sum of the parameters declared by + * all the features in use - this value is @nr_total_params. + * + * @name: name of the configuration - used for selection. + * @description: description of the purpose of the configuration. + * @item: list entry. + * @nr_feat_refs: Number of features used in this configuration. + * @feat_ref_names: references to features used in this configuration. + * @nr_presets: Number of sets of presets supplied by this configuration. + * @nr_total_params: Sum of all parameters declared by used features + * @presets: Array of preset values. + * + */ +struct cscfg_config_desc { + const char *name; + const char *description; + struct list_head item; + int nr_feat_refs; + const char **feat_ref_names; + int nr_presets; + int nr_total_params; + const u64 *presets; /* nr_presets * nr_total_params */ +}; + +#endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c index 1002605db8ba..8a18c71df37a 100644 --- a/drivers/hwtracing/coresight/coresight-core.c +++ b/drivers/hwtracing/coresight/coresight-core.c @@ -21,6 +21,7 @@ #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static DEFINE_MUTEX(coresight_mutex); static DEFINE_PER_CPU(struct coresight_device *, csdev_sink); @@ -1763,13 +1764,22 @@ static int __init coresight_init(void) ret = etm_perf_init(); if (ret) - bus_unregister(&coresight_bustype); + goto exit_bus_unregister; + /* initialise the coresight syscfg API */ + ret = cscfg_init(); + if (!ret) + return 0; + + etm_perf_exit(); +exit_bus_unregister: + bus_unregister(&coresight_bustype); return ret; } static void __exit coresight_exit(void) { + cscfg_exit(); etm_perf_exit(); bus_unregister(&coresight_bustype); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index 6f398377fec9..b582e92cdea4 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -748,7 +748,7 @@ int __init etm_perf_init(void) return ret; } -void __exit etm_perf_exit(void) +void etm_perf_exit(void) { perf_pmu_unregister(&etm_pmu); } diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 3e4f2ad5e193..29d90dfeba31 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -83,6 +83,6 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) #endif /* CONFIG_CORESIGHT */ int __init etm_perf_init(void); -void __exit etm_perf_exit(void); +void etm_perf_exit(void); #endif diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c new file mode 100644 index 000000000000..417db3f92c2f --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach + */ + +#include + +#include "coresight-config.h" +#include "coresight-syscfg.h" + +/* + * cscfg_ API manages configurations and features for the entire coresight + * infrastructure. + * + * It allows the loading of configurations and features, and loads these into + * coresight devices as appropriate. + */ + +/* protect the cscsg_data and device */ +static DEFINE_MUTEX(cscfg_mutex); + +/* only one of these */ +static struct cscfg_manager *cscfg_mgr; + +/* load features and configuations into the lists */ + +/* check feature list for a named feature - call with mutex locked. */ +static bool cscfg_match_list_feat(const char *name) +{ + struct cscfg_feature_desc *feat_desc; + + list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) { + if (strcmp(feat_desc->name, name) == 0) + return true; + } + return false; +} + +/* check all feat needed for cfg are in the list - call with mutex locked. */ +static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc) +{ + int i; + + for (i = 0; i < config_desc->nr_feat_refs; i++) + if (!cscfg_match_list_feat(config_desc->feat_ref_names[i])) + return -EINVAL; + return 0; +} + +/* + * load feature - add to feature list. + */ +static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) +{ + list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list); + + return 0; +} + +/* + * load config into the system - validate used features exist then add to + * config list. + */ +static int cscfg_load_config(struct cscfg_config_desc *config_desc) +{ + int err; + + /* validate features are present */ + err = cscfg_check_feat_for_cfg(config_desc); + if (err) + return err; + + list_add(&config_desc->item, &cscfg_mgr->config_desc_list); + return 0; +} + +/** + * cscfg_load_config_sets - API function to load feature and config sets. + * + * Take a 0 terminated array of feature descriptors and/or configuration + * descriptors and load into the system. + * Features are loaded first to ensure configuration dependencies can be met. + * + * @config_descs: 0 terminated array of configuration descriptors. + * @feat_descs: 0 terminated array of feature descriptors. + */ +int cscfg_load_config_sets(struct cscfg_config_desc **config_descs, + struct cscfg_feature_desc **feat_descs) +{ + int err, i = 0; + + mutex_lock(&cscfg_mutex); + + /* load features first */ + if (feat_descs) { + while (feat_descs[i]) { + err = cscfg_load_feat(feat_descs[i]); + if (err) { + pr_err("coresight-syscfg: Failed to load feature %s\n", + feat_descs[i]->name); + goto exit_unlock; + } + i++; + } + } + + /* next any configurations to check feature dependencies */ + i = 0; + if (config_descs) { + while (config_descs[i]) { + err = cscfg_load_config(config_descs[i]); + if (err) { + pr_err("coresight-syscfg: Failed to load configuration %s\n", + config_descs[i]->name); + goto exit_unlock; + } + i++; + } + } + +exit_unlock: + mutex_unlock(&cscfg_mutex); + return err; +} +EXPORT_SYMBOL_GPL(cscfg_load_config_sets); + +/* Initialise system configuration management device. */ + +struct device *cscfg_device(void) +{ + return cscfg_mgr ? &cscfg_mgr->dev : NULL; +} + +/* Must have a release function or the kernel will complain on module unload */ +static void cscfg_dev_release(struct device *dev) +{ + kfree(cscfg_mgr); + cscfg_mgr = NULL; +} + +/* a device is needed to "own" some kernel elements such as sysfs entries. */ +static int cscfg_create_device(void) +{ + struct device *dev; + int err = -ENOMEM; + + mutex_lock(&cscfg_mutex); + if (cscfg_mgr) { + err = -EINVAL; + goto create_dev_exit_unlock; + } + + cscfg_mgr = kzalloc(sizeof(struct cscfg_manager), GFP_KERNEL); + if (!cscfg_mgr) + goto create_dev_exit_unlock; + + /* setup the device */ + dev = cscfg_device(); + dev->release = cscfg_dev_release; + dev->init_name = "cs_system_cfg"; + + err = device_register(dev); + if (err) + cscfg_dev_release(dev); + +create_dev_exit_unlock: + mutex_unlock(&cscfg_mutex); + return err; +} + +static void cscfg_clear_device(void) +{ + mutex_lock(&cscfg_mutex); + device_unregister(cscfg_device()); + mutex_unlock(&cscfg_mutex); +} + +/* Initialise system config management API device */ +int __init cscfg_init(void) +{ + int err = 0; + + err = cscfg_create_device(); + if (err) + return err; + + INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list); + INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list); + INIT_LIST_HEAD(&cscfg_mgr->config_desc_list); + + dev_info(cscfg_device(), "CoreSight Configuration manager initialised"); + return 0; +} + +void cscfg_exit(void) +{ + cscfg_clear_device(); +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h new file mode 100644 index 000000000000..18be9b58cd0b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Coresight system configuration driver. + */ + +#ifndef CORESIGHT_SYSCFG_H +#define CORESIGHT_SYSCFG_H + +#include +#include + +#include "coresight-config.h" + +/** + * System configuration manager device. + * + * Contains lists of the loaded configurations and features, plus a list of CoreSight devices + * registered with the system as supporting configuration management. + * + * Need a device to 'own' some coresight system wide sysfs entries in + * perf events, configfs etc. + * + * @dev: The device. + * @csdev_desc_list: List of coresight devices registered with the configuration manager. + * @feat_desc_list: List of feature descriptors to load into registered devices. + * @config_desc_list: List of system configuration descriptors to load into registered devices. + */ +struct cscfg_manager { + struct device dev; + struct list_head csdev_desc_list; + struct list_head feat_desc_list; + struct list_head config_desc_list; +}; + +/* get reference to dev in cscfg_manager */ +struct device *cscfg_device(void); + +/* internal core operations for cscfg */ +int __init cscfg_init(void); +void cscfg_exit(void); + +/* syscfg manager external API */ +int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, + struct cscfg_feature_desc **feat_descs); + +#endif /* CORESIGHT_SYSCFG_H */ -- cgit v1.2.3 From 42ff700f3112babac129f4ae33023a7b7ce40a29 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:13 -0600 Subject: coresight: syscfg: Add registration and feature loading for cs devices API for individual devices to register with the syscfg management system is added. Devices register with matching information, and any features or configurations that match will be loaded into the device. The feature and configuration loading is extended so that on load these are loaded into any currently registered devices. This allows configuration loading after devices have been registered. Link: https://lore.kernel.org/r/20210723165444.1048-3-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-3-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-config.h | 98 +++++++ drivers/hwtracing/coresight/coresight-syscfg.c | 338 ++++++++++++++++++++++++- drivers/hwtracing/coresight/coresight-syscfg.h | 19 ++ include/linux/coresight.h | 7 + 4 files changed, 461 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 21aa7464dcdc..685fb46ce893 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -139,4 +139,102 @@ struct cscfg_config_desc { const u64 *presets; /* nr_presets * nr_total_params */ }; +/** + * config register instance - part of a loaded feature. + * maps register values to csdev driver structures + * + * @reg_desc: value to use when setting feature on device / store for + * readback of volatile values. + * @driver_regval: pointer to internal driver element used to set the value + * in hardware. + */ +struct cscfg_regval_csdev { + struct cscfg_regval_desc reg_desc; + void *driver_regval; +}; + +/** + * config parameter instance - part of a loaded feature. + * + * @feat_csdev: parent feature + * @reg_csdev: register value updated by this parameter. + * @current_value: current value of parameter - may be set by user via + * sysfs, or modified during device operation. + * @val64: true if 64 bit value + */ +struct cscfg_parameter_csdev { + struct cscfg_feature_csdev *feat_csdev; + struct cscfg_regval_csdev *reg_csdev; + u64 current_value; + bool val64; +}; + +/** + * Feature instance loaded into a CoreSight device. + * + * When a feature is loaded into a specific device, then this structure holds + * the connections between the register / parameter values used and the + * internal data structures that are written when the feature is enabled. + * + * Since applying a feature modifies internal data structures in the device, + * then we have a reference to the device spinlock to protect access to these + * structures (@drv_spinlock). + * + * @feat_desc: pointer to the static descriptor for this feature. + * @csdev: parent CoreSight device instance. + * @node: list entry into feature list for this device. + * @drv_spinlock: device spinlock for access to driver register data. + * @nr_params: number of parameters. + * @params_csdev: current parameter values on this device + * @nr_regs: number of registers to be programmed. + * @regs_csdev: Programming details for the registers + */ +struct cscfg_feature_csdev { + const struct cscfg_feature_desc *feat_desc; + struct coresight_device *csdev; + struct list_head node; + spinlock_t *drv_spinlock; + int nr_params; + struct cscfg_parameter_csdev *params_csdev; + int nr_regs; + struct cscfg_regval_csdev *regs_csdev; +}; + +/** + * Configuration instance when loaded into a CoreSight device. + * + * The instance contains references to loaded features on this device that are + * used by the configuration. + * + * @config_desc:reference to the descriptor for this configuration + * @csdev: parent coresight device for this configuration instance. + * @enabled: true if configuration is enabled on this device. + * @node: list entry within the coresight device + * @nr_feat: Number of features on this device that are used in the + * configuration. + * @feats_csdev:references to the device features to enable. + */ +struct cscfg_config_csdev { + const struct cscfg_config_desc *config_desc; + struct coresight_device *csdev; + bool enabled; + struct list_head node; + int nr_feat; + struct cscfg_feature_csdev *feats_csdev[0]; +}; + +/** + * Coresight device operations. + * + * Registered coresight devices provide these operations to manage feature + * instances compatible with the device hardware and drivers + * + * @load_feat: Pass a feature descriptor into the device and create the + * loaded feature instance (struct cscfg_feature_csdev). + */ +struct cscfg_csdev_feat_ops { + int (*load_feat)(struct coresight_device *csdev, + struct cscfg_feature_csdev *feat_csdev); +}; + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 417db3f92c2f..2c0d4906e226 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -25,6 +25,198 @@ static struct cscfg_manager *cscfg_mgr; /* load features and configuations into the lists */ +/* get name feature instance from a coresight device list of features */ +static struct cscfg_feature_csdev * +cscfg_get_feat_csdev(struct coresight_device *csdev, const char *name) +{ + struct cscfg_feature_csdev *feat_csdev = NULL; + + list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) { + if (strcmp(feat_csdev->feat_desc->name, name) == 0) + return feat_csdev; + } + return NULL; +} + +/* allocate the device config instance - with max number of used features */ +static struct cscfg_config_csdev * +cscfg_alloc_csdev_cfg(struct coresight_device *csdev, int nr_feats) +{ + struct cscfg_config_csdev *config_csdev = NULL; + struct device *dev = csdev->dev.parent; + + /* this is being allocated using the devm for the coresight device */ + config_csdev = devm_kzalloc(dev, + offsetof(struct cscfg_config_csdev, feats_csdev[nr_feats]), + GFP_KERNEL); + if (!config_csdev) + return NULL; + + config_csdev->csdev = csdev; + return config_csdev; +} + +/* Load a config into a device if there are any feature matches between config and device */ +static int cscfg_add_csdev_cfg(struct coresight_device *csdev, + struct cscfg_config_desc *config_desc) +{ + struct cscfg_config_csdev *config_csdev = NULL; + struct cscfg_feature_csdev *feat_csdev; + unsigned long flags; + int i; + + /* look at each required feature and see if it matches any feature on the device */ + for (i = 0; i < config_desc->nr_feat_refs; i++) { + /* look for a matching name */ + feat_csdev = cscfg_get_feat_csdev(csdev, config_desc->feat_ref_names[i]); + if (feat_csdev) { + /* + * At least one feature on this device matches the config + * add a config instance to the device and a reference to the feature. + */ + if (!config_csdev) { + config_csdev = cscfg_alloc_csdev_cfg(csdev, + config_desc->nr_feat_refs); + if (!config_csdev) + return -ENOMEM; + config_csdev->config_desc = config_desc; + } + config_csdev->feats_csdev[config_csdev->nr_feat++] = feat_csdev; + } + } + /* if matched features, add config to device.*/ + if (config_csdev) { + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + list_add(&config_csdev->node, &csdev->config_csdev_list); + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); + } + + return 0; +} + +/* + * Add the config to the set of registered devices - call with mutex locked. + * Iterates through devices - any device that matches one or more of the + * configuration features will load it, the others will ignore it. + */ +static int cscfg_add_cfg_to_csdevs(struct cscfg_config_desc *config_desc) +{ + struct cscfg_registered_csdev *csdev_item; + int err; + + list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) { + err = cscfg_add_csdev_cfg(csdev_item->csdev, config_desc); + if (err) + return err; + } + return 0; +} + +/* + * Allocate a feature object for load into a csdev. + * memory allocated using the csdev->dev object using devm managed allocator. + */ +static struct cscfg_feature_csdev * +cscfg_alloc_csdev_feat(struct coresight_device *csdev, struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_feature_csdev *feat_csdev = NULL; + struct device *dev = csdev->dev.parent; + int i; + + feat_csdev = devm_kzalloc(dev, sizeof(struct cscfg_feature_csdev), GFP_KERNEL); + if (!feat_csdev) + return NULL; + + /* parameters are optional - could be 0 */ + feat_csdev->nr_params = feat_desc->nr_params; + + /* + * if we need parameters, zero alloc the space here, the load routine in + * the csdev device driver will fill out some information according to + * feature descriptor. + */ + if (feat_csdev->nr_params) { + feat_csdev->params_csdev = devm_kcalloc(dev, feat_csdev->nr_params, + sizeof(struct cscfg_parameter_csdev), + GFP_KERNEL); + if (!feat_csdev->params_csdev) + return NULL; + + /* + * fill in the feature reference in the param - other fields + * handled by loader in csdev. + */ + for (i = 0; i < feat_csdev->nr_params; i++) + feat_csdev->params_csdev[i].feat_csdev = feat_csdev; + } + + /* + * Always have registers to program - again the load routine in csdev device + * will fill out according to feature descriptor and device requirements. + */ + feat_csdev->nr_regs = feat_desc->nr_regs; + feat_csdev->regs_csdev = devm_kcalloc(dev, feat_csdev->nr_regs, + sizeof(struct cscfg_regval_csdev), + GFP_KERNEL); + if (!feat_csdev->regs_csdev) + return NULL; + + /* load the feature default values */ + feat_csdev->feat_desc = feat_desc; + feat_csdev->csdev = csdev; + + return feat_csdev; +} + +/* load one feature into one coresight device */ +static int cscfg_load_feat_csdev(struct coresight_device *csdev, + struct cscfg_feature_desc *feat_desc, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_feature_csdev *feat_csdev; + unsigned long flags; + int err; + + if (!ops->load_feat) + return -EINVAL; + + feat_csdev = cscfg_alloc_csdev_feat(csdev, feat_desc); + if (!feat_csdev) + return -ENOMEM; + + /* load the feature into the device */ + err = ops->load_feat(csdev, feat_csdev); + if (err) + return err; + + /* add to internal csdev feature list */ + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + list_add(&feat_csdev->node, &csdev->feature_csdev_list); + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); + + return 0; +} + +/* + * Add feature to any matching devices - call with mutex locked. + * Iterates through devices - any device that matches the feature will be + * called to load it. + */ +static int cscfg_add_feat_to_csdevs(struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_registered_csdev *csdev_item; + int err; + + list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) { + if (csdev_item->match_flags & feat_desc->match_flags) { + err = cscfg_load_feat_csdev(csdev_item->csdev, feat_desc, &csdev_item->ops); + if (err) + return err; + } + } + return 0; +} + /* check feature list for a named feature - call with mutex locked. */ static bool cscfg_match_list_feat(const char *name) { @@ -53,8 +245,14 @@ static int cscfg_check_feat_for_cfg(struct cscfg_config_desc *config_desc) */ static int cscfg_load_feat(struct cscfg_feature_desc *feat_desc) { - list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list); + int err; + + /* add feature to any matching registered devices */ + err = cscfg_add_feat_to_csdevs(feat_desc); + if (err) + return err; + list_add(&feat_desc->item, &cscfg_mgr->feat_desc_list); return 0; } @@ -71,6 +269,11 @@ static int cscfg_load_config(struct cscfg_config_desc *config_desc) if (err) return err; + /* add config to any matching registered device */ + err = cscfg_add_cfg_to_csdevs(config_desc); + if (err) + return err; + list_add(&config_desc->item, &cscfg_mgr->config_desc_list); return 0; } @@ -125,6 +328,139 @@ exit_unlock: } EXPORT_SYMBOL_GPL(cscfg_load_config_sets); +/* Handle coresight device registration and add configs and features to devices */ + +/* iterate through config lists and load matching configs to device */ +static int cscfg_add_cfgs_csdev(struct coresight_device *csdev) +{ + struct cscfg_config_desc *config_desc; + int err = 0; + + list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { + err = cscfg_add_csdev_cfg(csdev, config_desc); + if (err) + break; + } + return err; +} + +/* iterate through feature lists and load matching features to device */ +static int cscfg_add_feats_csdev(struct coresight_device *csdev, + u32 match_flags, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_feature_desc *feat_desc; + int err = 0; + + if (!ops->load_feat) + return -EINVAL; + + list_for_each_entry(feat_desc, &cscfg_mgr->feat_desc_list, item) { + if (feat_desc->match_flags & match_flags) { + err = cscfg_load_feat_csdev(csdev, feat_desc, ops); + if (err) + break; + } + } + return err; +} + +/* Add coresight device to list and copy its matching info */ +static int cscfg_list_add_csdev(struct coresight_device *csdev, + u32 match_flags, + struct cscfg_csdev_feat_ops *ops) +{ + struct cscfg_registered_csdev *csdev_item; + + /* allocate the list entry structure */ + csdev_item = kzalloc(sizeof(struct cscfg_registered_csdev), GFP_KERNEL); + if (!csdev_item) + return -ENOMEM; + + csdev_item->csdev = csdev; + csdev_item->match_flags = match_flags; + csdev_item->ops.load_feat = ops->load_feat; + list_add(&csdev_item->item, &cscfg_mgr->csdev_desc_list); + + INIT_LIST_HEAD(&csdev->feature_csdev_list); + INIT_LIST_HEAD(&csdev->config_csdev_list); + spin_lock_init(&csdev->cscfg_csdev_lock); + + return 0; +} + +/* remove a coresight device from the list and free data */ +static void cscfg_list_remove_csdev(struct coresight_device *csdev) +{ + struct cscfg_registered_csdev *csdev_item, *tmp; + + list_for_each_entry_safe(csdev_item, tmp, &cscfg_mgr->csdev_desc_list, item) { + if (csdev_item->csdev == csdev) { + list_del(&csdev_item->item); + kfree(csdev_item); + break; + } + } +} + +/** + * cscfg_register_csdev - register a coresight device with the syscfg manager. + * + * Registers the coresight device with the system. @match_flags used to check + * if the device is a match for registered features. Any currently registered + * configurations and features that match the device will be loaded onto it. + * + * @csdev: The coresight device to register. + * @match_flags: Matching information to load features. + * @ops: Standard operations supported by the device. + */ +int cscfg_register_csdev(struct coresight_device *csdev, + u32 match_flags, + struct cscfg_csdev_feat_ops *ops) +{ + int ret = 0; + + mutex_lock(&cscfg_mutex); + + /* add device to list of registered devices */ + ret = cscfg_list_add_csdev(csdev, match_flags, ops); + if (ret) + goto reg_csdev_unlock; + + /* now load any registered features and configs matching the device. */ + ret = cscfg_add_feats_csdev(csdev, match_flags, ops); + if (ret) { + cscfg_list_remove_csdev(csdev); + goto reg_csdev_unlock; + } + + ret = cscfg_add_cfgs_csdev(csdev); + if (ret) { + cscfg_list_remove_csdev(csdev); + goto reg_csdev_unlock; + } + + pr_info("CSCFG registered %s", dev_name(&csdev->dev)); + +reg_csdev_unlock: + mutex_unlock(&cscfg_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(cscfg_register_csdev); + +/** + * cscfg_unregister_csdev - remove coresight device from syscfg manager. + * + * @csdev: Device to remove. + */ +void cscfg_unregister_csdev(struct coresight_device *csdev) +{ + mutex_lock(&cscfg_mutex); + cscfg_list_remove_csdev(csdev); + mutex_unlock(&cscfg_mutex); +} +EXPORT_SYMBOL_GPL(cscfg_unregister_csdev); + /* Initialise system configuration management device. */ struct device *cscfg_device(void) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 18be9b58cd0b..5bcae3b374c6 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -35,6 +35,22 @@ struct cscfg_manager { /* get reference to dev in cscfg_manager */ struct device *cscfg_device(void); +/** + * List entry for Coresight devices that are registered as supporting complex + * config operations. + * + * @csdev: The registered device. + * @match_flags: The matching type information for adding features. + * @ops: Operations supported by the registered device. + * @item: list entry. + */ +struct cscfg_registered_csdev { + struct coresight_device *csdev; + u32 match_flags; + struct cscfg_csdev_feat_ops ops; + struct list_head item; +}; + /* internal core operations for cscfg */ int __init cscfg_init(void); void cscfg_exit(void); @@ -42,5 +58,8 @@ void cscfg_exit(void); /* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, struct cscfg_feature_desc **feat_descs); +int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags, + struct cscfg_csdev_feat_ops *ops); +void cscfg_unregister_csdev(struct coresight_device *csdev); #endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 85008a65e21f..16544ae2b532 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -220,6 +220,9 @@ struct coresight_sysfs_link { * @nr_links: number of sysfs links created to other components from this * device. These will appear in the "connections" group. * @has_conns_grp: Have added a "connections" group for sysfs links. + * @feature_csdev_list: List of complex feature programming added to the device. + * @config_csdev_list: List of system configurations added to the device. + * @cscfg_csdev_lock: Protect the lists of configurations and features. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -241,6 +244,10 @@ struct coresight_device { int nr_links; bool has_conns_grp; bool ect_enabled; /* true only if associated ect device is enabled */ + /* system configuration and feature lists */ + struct list_head feature_csdev_list; + struct list_head config_csdev_list; + spinlock_t cscfg_csdev_lock; }; /* -- cgit v1.2.3 From f53e93ac8cf705fffdefe79573ce001d81c3c6fe Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:14 -0600 Subject: coresight: config: Add configuration and feature generic functions Adds a set of generic support functions that allow devices to set and save features values on the device, and enable and disable configurations. Additional functions for other common operations including feature reset. Link: https://lore.kernel.org/r/20210723165444.1048-4-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-4-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Makefile | 2 +- drivers/hwtracing/coresight/coresight-config.c | 272 +++++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-config.h | 9 + drivers/hwtracing/coresight/coresight-syscfg.c | 3 +- 4 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-config.c diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 3d037f17aade..63ecfc3cf66d 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,7 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o coresight-syscfg.o + coresight-sysfs.o coresight-syscfg.o coresight-config.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-config.c b/drivers/hwtracing/coresight/coresight-config.c new file mode 100644 index 000000000000..4723bf7402a2 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-config.c @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach + */ + +#include +#include "coresight-config.h" +#include "coresight-priv.h" + +/* + * This provides a set of generic functions that operate on configurations + * and features to manage the handling of parameters, the programming and + * saving of registers used by features on devices. + */ + +/* + * Write the value held in the register structure into the driver internal memory + * location. + */ +static void cscfg_set_reg(struct cscfg_regval_csdev *reg_csdev) +{ + u32 *p_val32 = (u32 *)reg_csdev->driver_regval; + u32 tmp32 = reg_csdev->reg_desc.val32; + + if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) { + *((u64 *)reg_csdev->driver_regval) = reg_csdev->reg_desc.val64; + return; + } + + if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_MASK) { + tmp32 = *p_val32; + tmp32 &= ~reg_csdev->reg_desc.mask32; + tmp32 |= reg_csdev->reg_desc.val32 & reg_csdev->reg_desc.mask32; + } + *p_val32 = tmp32; +} + +/* + * Read the driver value into the reg if this is marked as one we want to save. + */ +static void cscfg_save_reg(struct cscfg_regval_csdev *reg_csdev) +{ + if (!(reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_SAVE)) + return; + if (reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT) + reg_csdev->reg_desc.val64 = *(u64 *)(reg_csdev->driver_regval); + else + reg_csdev->reg_desc.val32 = *(u32 *)(reg_csdev->driver_regval); +} + +/* + * Some register values are set from parameters. Initialise these registers + * from the current parameter values. + */ +static void cscfg_init_reg_param(struct cscfg_feature_csdev *feat_csdev, + struct cscfg_regval_desc *reg_desc, + struct cscfg_regval_csdev *reg_csdev) +{ + struct cscfg_parameter_csdev *param_csdev; + + /* for param, load routines have validated the index */ + param_csdev = &feat_csdev->params_csdev[reg_desc->param_idx]; + param_csdev->reg_csdev = reg_csdev; + param_csdev->val64 = reg_csdev->reg_desc.type & CS_CFG_REG_TYPE_VAL_64BIT; + + if (param_csdev->val64) + reg_csdev->reg_desc.val64 = param_csdev->current_value; + else + reg_csdev->reg_desc.val32 = (u32)param_csdev->current_value; +} + +/* set values into the driver locations referenced in cscfg_reg_csdev */ +static int cscfg_set_on_enable(struct cscfg_feature_csdev *feat_csdev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(feat_csdev->drv_spinlock, flags); + for (i = 0; i < feat_csdev->nr_regs; i++) + cscfg_set_reg(&feat_csdev->regs_csdev[i]); + spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags); + dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s", + feat_csdev->feat_desc->name, "set on enable"); + return 0; +} + +/* copy back values from the driver locations referenced in cscfg_reg_csdev */ +static void cscfg_save_on_disable(struct cscfg_feature_csdev *feat_csdev) +{ + unsigned long flags; + int i; + + spin_lock_irqsave(feat_csdev->drv_spinlock, flags); + for (i = 0; i < feat_csdev->nr_regs; i++) + cscfg_save_reg(&feat_csdev->regs_csdev[i]); + spin_unlock_irqrestore(feat_csdev->drv_spinlock, flags); + dev_dbg(&feat_csdev->csdev->dev, "Feature %s: %s", + feat_csdev->feat_desc->name, "save on disable"); +} + +/* default reset - restore default values */ +void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev) +{ + struct cscfg_regval_desc *reg_desc; + struct cscfg_regval_csdev *reg_csdev; + int i; + + /* + * set the default values for all parameters and regs from the + * relevant static descriptors. + */ + for (i = 0; i < feat_csdev->nr_params; i++) + feat_csdev->params_csdev[i].current_value = + feat_csdev->feat_desc->params_desc[i].value; + + for (i = 0; i < feat_csdev->nr_regs; i++) { + reg_desc = &feat_csdev->feat_desc->regs_desc[i]; + reg_csdev = &feat_csdev->regs_csdev[i]; + reg_csdev->reg_desc.type = reg_desc->type; + + /* check if reg set from a parameter otherwise desc default */ + if (reg_desc->type & CS_CFG_REG_TYPE_VAL_PARAM) + cscfg_init_reg_param(feat_csdev, reg_desc, reg_csdev); + else + /* + * for normal values the union between val64 & val32 + mask32 + * allows us to init using the 64 bit value + */ + reg_csdev->reg_desc.val64 = reg_desc->val64; + } +} + +/* + * For the selected presets, we set the register associated with the parameter, to + * the value of the preset index associated with the parameter. + */ +static int cscfg_update_presets(struct cscfg_config_csdev *config_csdev, int preset) +{ + int i, j, val_idx = 0, nr_cfg_params; + struct cscfg_parameter_csdev *param_csdev; + struct cscfg_feature_csdev *feat_csdev; + const struct cscfg_config_desc *config_desc = config_csdev->config_desc; + const char *name; + const u64 *preset_base; + u64 val; + + /* preset in range 1 to nr_presets */ + if (preset < 1 || preset > config_desc->nr_presets) + return -EINVAL; + /* + * Go through the array of features, assigning preset values to + * feature parameters in the order they appear. + * There should be precisely the same number of preset values as the + * sum of number of parameters over all the features - but we will + * ensure there is no overrun. + */ + nr_cfg_params = config_desc->nr_total_params; + preset_base = &config_desc->presets[(preset - 1) * nr_cfg_params]; + for (i = 0; i < config_csdev->nr_feat; i++) { + feat_csdev = config_csdev->feats_csdev[i]; + if (!feat_csdev->nr_params) + continue; + + for (j = 0; j < feat_csdev->nr_params; j++) { + param_csdev = &feat_csdev->params_csdev[j]; + name = feat_csdev->feat_desc->params_desc[j].name; + val = preset_base[val_idx++]; + if (param_csdev->val64) { + dev_dbg(&config_csdev->csdev->dev, + "set param %s (%lld)", name, val); + param_csdev->reg_csdev->reg_desc.val64 = val; + } else { + param_csdev->reg_csdev->reg_desc.val32 = (u32)val; + dev_dbg(&config_csdev->csdev->dev, + "set param %s (%d)", name, (u32)val); + } + } + + /* exit early if all params filled */ + if (val_idx >= nr_cfg_params) + break; + } + return 0; +} + +/* + * if we are not using a preset, then need to update the feature params + * with current values. This sets the register associated with the parameter + * with the current value of that parameter. + */ +static int cscfg_update_curr_params(struct cscfg_config_csdev *config_csdev) +{ + int i, j; + struct cscfg_feature_csdev *feat_csdev; + struct cscfg_parameter_csdev *param_csdev; + const char *name; + u64 val; + + for (i = 0; i < config_csdev->nr_feat; i++) { + feat_csdev = config_csdev->feats_csdev[i]; + if (!feat_csdev->nr_params) + continue; + for (j = 0; j < feat_csdev->nr_params; j++) { + param_csdev = &feat_csdev->params_csdev[j]; + name = feat_csdev->feat_desc->params_desc[j].name; + val = param_csdev->current_value; + if (param_csdev->val64) { + dev_dbg(&config_csdev->csdev->dev, + "set param %s (%lld)", name, val); + param_csdev->reg_csdev->reg_desc.val64 = val; + } else { + param_csdev->reg_csdev->reg_desc.val32 = (u32)val; + dev_dbg(&config_csdev->csdev->dev, + "set param %s (%d)", name, (u32)val); + } + } + } + return 0; +} + +/* + * Configuration values will be programmed into the driver locations if enabling, or read + * from relevant locations on disable. + */ +static int cscfg_prog_config(struct cscfg_config_csdev *config_csdev, bool enable) +{ + int i, err = 0; + struct cscfg_feature_csdev *feat_csdev; + struct coresight_device *csdev; + + for (i = 0; i < config_csdev->nr_feat; i++) { + feat_csdev = config_csdev->feats_csdev[i]; + csdev = feat_csdev->csdev; + dev_dbg(&csdev->dev, "cfg %s; %s feature:%s", config_csdev->config_desc->name, + enable ? "enable" : "disable", feat_csdev->feat_desc->name); + + if (enable) + err = cscfg_set_on_enable(feat_csdev); + else + cscfg_save_on_disable(feat_csdev); + + if (err) + break; + } + return err; +} + +/* + * Enable configuration for the device. Will result in the internal driver data + * being updated ready for programming into the device. + * + * @config_csdev: config_csdev to set. + * @preset: preset values to use - 0 for default. + */ +int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset) +{ + int err = 0; + + if (preset) + err = cscfg_update_presets(config_csdev, preset); + else + err = cscfg_update_curr_params(config_csdev); + if (!err) + err = cscfg_prog_config(config_csdev, true); + return err; +} + +void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev) +{ + cscfg_prog_config(config_csdev, false); +} diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 685fb46ce893..5a39cbbc38a4 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -237,4 +237,13 @@ struct cscfg_csdev_feat_ops { struct cscfg_feature_csdev *feat_csdev); }; +/* coresight config helper functions*/ + +/* enable / disable config on a device - called with appropriate locks set.*/ +int cscfg_csdev_enable_config(struct cscfg_config_csdev *config_csdev, int preset); +void cscfg_csdev_disable_config(struct cscfg_config_csdev *config_csdev); + +/* reset a feature to default values */ +void cscfg_reset_feat(struct cscfg_feature_csdev *feat_csdev); + #endif /* _CORESIGHT_CORESIGHT_CONFIG_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 2c0d4906e226..5e4bd86f369e 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -189,7 +189,8 @@ static int cscfg_load_feat_csdev(struct coresight_device *csdev, if (err) return err; - /* add to internal csdev feature list */ + /* add to internal csdev feature list & initialise using reset call */ + cscfg_reset_feat(feat_csdev); spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); list_add(&feat_csdev->node, &csdev->feature_csdev_list); spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); -- cgit v1.2.3 From 94d2bac540762e7517933d365dd6289f54963c97 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:15 -0600 Subject: coresight: etm-perf: Update to handle configuration selection Loaded coresight configurations are registered in the cs_etm\events sub directory. This extends the etm-perf code to handle these registrations, and the cs_syscfg driver to perform the registration on load. Link: https://lore.kernel.org/r/20210723165444.1048-5-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-5-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-config.h | 2 + drivers/hwtracing/coresight/coresight-etm-perf.c | 134 ++++++++++++++++++----- drivers/hwtracing/coresight/coresight-etm-perf.h | 8 ++ drivers/hwtracing/coresight/coresight-syscfg.c | 11 ++ 4 files changed, 127 insertions(+), 28 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 5a39cbbc38a4..0667581822c1 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -126,6 +126,7 @@ struct cscfg_feature_desc { * @nr_presets: Number of sets of presets supplied by this configuration. * @nr_total_params: Sum of all parameters declared by used features * @presets: Array of preset values. + * @event_ea: Extended attribute for perf event value * */ struct cscfg_config_desc { @@ -137,6 +138,7 @@ struct cscfg_config_desc { int nr_presets; int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ + struct dev_ext_attribute *event_ea; }; /** diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index b582e92cdea4..e42ab919ddc3 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -18,8 +18,10 @@ #include #include +#include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static struct pmu etm_pmu; static bool etm_perf_up; @@ -57,8 +59,13 @@ PMU_FORMAT_ATTR(contextid1, "config:" __stringify(ETM_OPT_CTXTID)); PMU_FORMAT_ATTR(contextid2, "config:" __stringify(ETM_OPT_CTXTID2)); PMU_FORMAT_ATTR(timestamp, "config:" __stringify(ETM_OPT_TS)); PMU_FORMAT_ATTR(retstack, "config:" __stringify(ETM_OPT_RETSTK)); +/* preset - if sink ID is used as a configuration selector */ +PMU_FORMAT_ATTR(preset, "config:0-3"); /* Sink ID - same for all ETMs */ PMU_FORMAT_ATTR(sinkid, "config2:0-31"); +/* config ID - set if a system configuration is selected */ +PMU_FORMAT_ATTR(configid, "config2:32-63"); + /* * contextid always traces the "PID". The PID is in CONTEXTIDR_EL1 @@ -88,6 +95,8 @@ static struct attribute *etm_config_formats_attr[] = { &format_attr_timestamp.attr, &format_attr_retstack.attr, &format_attr_sinkid.attr, + &format_attr_preset.attr, + &format_attr_configid.attr, NULL, }; @@ -105,9 +114,19 @@ static const struct attribute_group etm_pmu_sinks_group = { .attrs = etm_config_sinks_attr, }; +static struct attribute *etm_config_events_attr[] = { + NULL, +}; + +static const struct attribute_group etm_pmu_events_group = { + .name = "events", + .attrs = etm_config_events_attr, +}; + static const struct attribute_group *etm_pmu_attr_groups[] = { &etm_pmu_format_group, &etm_pmu_sinks_group, + &etm_pmu_events_group, NULL, }; @@ -286,7 +305,7 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, INIT_WORK(&event_data->work, free_event_data); /* First get the selected sink from user space. */ - if (event->attr.config2) { + if (event->attr.config2 & GENMASK_ULL(31, 0)) { id = (u32)event->attr.config2; sink = user_sink = coresight_get_sink_by_id(id); } @@ -658,68 +677,127 @@ static ssize_t etm_perf_sink_name_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)(ea->var)); } -int etm_perf_add_symlink_sink(struct coresight_device *csdev) +static struct dev_ext_attribute * +etm_perf_add_symlink_group(struct device *dev, const char *name, const char *group_name) { - int ret; + struct dev_ext_attribute *ea; unsigned long hash; - const char *name; + int ret; struct device *pmu_dev = etm_pmu.dev; - struct device *dev = &csdev->dev; - struct dev_ext_attribute *ea; - - if (csdev->type != CORESIGHT_DEV_TYPE_SINK && - csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) - return -EINVAL; - - if (csdev->ea != NULL) - return -EINVAL; if (!etm_perf_up) - return -EPROBE_DEFER; + return ERR_PTR(-EPROBE_DEFER); ea = devm_kzalloc(dev, sizeof(*ea), GFP_KERNEL); if (!ea) - return -ENOMEM; + return ERR_PTR(-ENOMEM); - name = dev_name(dev); - /* See function coresight_get_sink_by_id() to know where this is used */ + /* + * If this function is called adding a sink then the hash is used for + * sink selection - see function coresight_get_sink_by_id(). + * If adding a configuration then the hash is used for selection in + * cscfg_activate_config() + */ hash = hashlen_hash(hashlen_string(NULL, name)); sysfs_attr_init(&ea->attr.attr); ea->attr.attr.name = devm_kstrdup(dev, name, GFP_KERNEL); if (!ea->attr.attr.name) - return -ENOMEM; + return ERR_PTR(-ENOMEM); ea->attr.attr.mode = 0444; - ea->attr.show = etm_perf_sink_name_show; ea->var = (unsigned long *)hash; ret = sysfs_add_file_to_group(&pmu_dev->kobj, - &ea->attr.attr, "sinks"); + &ea->attr.attr, group_name); - if (!ret) - csdev->ea = ea; + return ret ? ERR_PTR(ret) : ea; +} - return ret; +int etm_perf_add_symlink_sink(struct coresight_device *csdev) +{ + const char *name; + struct device *dev = &csdev->dev; + int err = 0; + + if (csdev->type != CORESIGHT_DEV_TYPE_SINK && + csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) + return -EINVAL; + + if (csdev->ea != NULL) + return -EINVAL; + + name = dev_name(dev); + csdev->ea = etm_perf_add_symlink_group(dev, name, "sinks"); + if (IS_ERR(csdev->ea)) { + err = PTR_ERR(csdev->ea); + csdev->ea = NULL; + } else + csdev->ea->attr.show = etm_perf_sink_name_show; + + return err; } -void etm_perf_del_symlink_sink(struct coresight_device *csdev) +static void etm_perf_del_symlink_group(struct dev_ext_attribute *ea, const char *group_name) { struct device *pmu_dev = etm_pmu.dev; - struct dev_ext_attribute *ea = csdev->ea; + sysfs_remove_file_from_group(&pmu_dev->kobj, + &ea->attr.attr, group_name); +} + +void etm_perf_del_symlink_sink(struct coresight_device *csdev) +{ if (csdev->type != CORESIGHT_DEV_TYPE_SINK && csdev->type != CORESIGHT_DEV_TYPE_LINKSINK) return; - if (!ea) + if (!csdev->ea) return; - sysfs_remove_file_from_group(&pmu_dev->kobj, - &ea->attr.attr, "sinks"); + etm_perf_del_symlink_group(csdev->ea, "sinks"); csdev->ea = NULL; } +static ssize_t etm_perf_cscfg_event_show(struct device *dev, + struct device_attribute *dattr, + char *buf) +{ + struct dev_ext_attribute *ea; + + ea = container_of(dattr, struct dev_ext_attribute, attr); + return scnprintf(buf, PAGE_SIZE, "configid=0x%lx\n", (unsigned long)(ea->var)); +} + +int etm_perf_add_symlink_cscfg(struct device *dev, struct cscfg_config_desc *config_desc) +{ + int err = 0; + + if (config_desc->event_ea != NULL) + return 0; + + config_desc->event_ea = etm_perf_add_symlink_group(dev, config_desc->name, "events"); + + /* set the show function to the custom cscfg event */ + if (!IS_ERR(config_desc->event_ea)) + config_desc->event_ea->attr.show = etm_perf_cscfg_event_show; + else { + err = PTR_ERR(config_desc->event_ea); + config_desc->event_ea = NULL; + } + + return err; +} + +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc) +{ + if (!config_desc->event_ea) + return; + + etm_perf_del_symlink_group(config_desc->event_ea, "events"); + config_desc->event_ea = NULL; +} + int __init etm_perf_init(void) { int ret; diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index 29d90dfeba31..ba617fe2217e 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -11,6 +11,7 @@ #include "coresight-priv.h" struct coresight_device; +struct cscfg_config_desc; /* * In both ETMv3 and v4 the maximum number of address comparator implentable @@ -69,6 +70,9 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) return data->snk_config; return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, + struct cscfg_config_desc *config_desc); +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc); #else static inline int etm_perf_symlink(struct coresight_device *csdev, bool link) { return -EINVAL; } @@ -79,6 +83,10 @@ static inline void *etm_perf_sink_config(struct perf_output_handle *handle) { return NULL; } +int etm_perf_add_symlink_cscfg(struct device *dev, + struct cscfg_config_desc *config_desc) +{ return -EINVAL; } +void etm_perf_del_symlink_cscfg(struct cscfg_config_desc *config_desc) {} #endif /* CONFIG_CORESIGHT */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 5e4bd86f369e..b93f2b4a777e 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -7,6 +7,7 @@ #include #include "coresight-config.h" +#include "coresight-etm-perf.h" #include "coresight-syscfg.h" /* @@ -275,6 +276,11 @@ static int cscfg_load_config(struct cscfg_config_desc *config_desc) if (err) return err; + /* add config to perf fs to allow selection */ + err = etm_perf_add_symlink_cscfg(cscfg_device(), config_desc); + if (err) + return err; + list_add(&config_desc->item, &cscfg_mgr->config_desc_list); return 0; } @@ -508,7 +514,12 @@ create_dev_exit_unlock: static void cscfg_clear_device(void) { + struct cscfg_config_desc *cfg_desc; + mutex_lock(&cscfg_mutex); + list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) { + etm_perf_del_symlink_cscfg(cfg_desc); + } device_unregister(cscfg_device()); mutex_unlock(&cscfg_mutex); } -- cgit v1.2.3 From f8cce2ff3c04361b8843d8489620fda8880f668b Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:16 -0600 Subject: coresight: syscfg: Add API to activate and enable configurations Configurations are first activated, then when any coresight device is enabled, the active configurations are checked and any matching one is enabled. This patch provides the activation / enable API. Link: https://lore.kernel.org/r/20210723165444.1048-6-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-6-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-config.h | 2 + drivers/hwtracing/coresight/coresight-syscfg.c | 215 +++++++++++++++++++++++++ drivers/hwtracing/coresight/coresight-syscfg.h | 8 + include/linux/coresight.h | 2 + 4 files changed, 227 insertions(+) diff --git a/drivers/hwtracing/coresight/coresight-config.h b/drivers/hwtracing/coresight/coresight-config.h index 0667581822c1..25eb6c632692 100644 --- a/drivers/hwtracing/coresight/coresight-config.h +++ b/drivers/hwtracing/coresight/coresight-config.h @@ -127,6 +127,7 @@ struct cscfg_feature_desc { * @nr_total_params: Sum of all parameters declared by used features * @presets: Array of preset values. * @event_ea: Extended attribute for perf event value + * @active_cnt: ref count for activate on this configuration. * */ struct cscfg_config_desc { @@ -139,6 +140,7 @@ struct cscfg_config_desc { int nr_total_params; const u64 *presets; /* nr_presets * nr_total_params */ struct dev_ext_attribute *event_ea; + atomic_t active_cnt; }; /** diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index b93f2b4a777e..795dba576fea 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -282,6 +282,7 @@ static int cscfg_load_config(struct cscfg_config_desc *config_desc) return err; list_add(&config_desc->item, &cscfg_mgr->config_desc_list); + atomic_set(&config_desc->active_cnt, 0); return 0; } @@ -468,6 +469,219 @@ void cscfg_unregister_csdev(struct coresight_device *csdev) } EXPORT_SYMBOL_GPL(cscfg_unregister_csdev); +/** + * cscfg_csdev_reset_feats - reset features for a CoreSight device. + * + * Resets all parameters and register values for any features loaded + * into @csdev to their default values. + * + * @csdev: The CoreSight device. + */ +void cscfg_csdev_reset_feats(struct coresight_device *csdev) +{ + struct cscfg_feature_csdev *feat_csdev; + unsigned long flags; + + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + if (list_empty(&csdev->feature_csdev_list)) + goto unlock_exit; + + list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) + cscfg_reset_feat(feat_csdev); + +unlock_exit: + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); +} +EXPORT_SYMBOL_GPL(cscfg_csdev_reset_feats); + +/** + * cscfg_activate_config - Mark a configuration descriptor as active. + * + * This will be seen when csdev devices are enabled in the system. + * Only activated configurations can be enabled on individual devices. + * Activation protects the configuration from alteration or removal while + * active. + * + * Selection by hash value - generated from the configuration name when it + * was loaded and added to the cs_etm/configurations file system for selection + * by perf. + * + * Increments the configuration descriptor active count and the global active + * count. + * + * @cfg_hash: Hash value of the selected configuration name. + */ +int cscfg_activate_config(unsigned long cfg_hash) +{ + struct cscfg_config_desc *config_desc; + int err = -EINVAL; + + mutex_lock(&cscfg_mutex); + + list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { + if ((unsigned long)config_desc->event_ea->var == cfg_hash) { + /* + * increment the global active count - control changes to + * active configurations + */ + atomic_inc(&cscfg_mgr->sys_active_cnt); + + /* + * mark the descriptor as active so enable config on a + * device instance will use it + */ + atomic_inc(&config_desc->active_cnt); + + err = 0; + dev_dbg(cscfg_device(), "Activate config %s.\n", config_desc->name); + break; + } + } + mutex_unlock(&cscfg_mutex); + + return err; +} +EXPORT_SYMBOL_GPL(cscfg_activate_config); + +/** + * cscfg_deactivate_config - Mark a config descriptor as inactive. + * + * Decrement the configuration and global active counts. + * + * @cfg_hash: Hash value of the selected configuration name. + */ +void cscfg_deactivate_config(unsigned long cfg_hash) +{ + struct cscfg_config_desc *config_desc; + + mutex_lock(&cscfg_mutex); + + list_for_each_entry(config_desc, &cscfg_mgr->config_desc_list, item) { + if ((unsigned long)config_desc->event_ea->var == cfg_hash) { + atomic_dec(&config_desc->active_cnt); + atomic_dec(&cscfg_mgr->sys_active_cnt); + dev_dbg(cscfg_device(), "Deactivate config %s.\n", config_desc->name); + break; + } + } + mutex_unlock(&cscfg_mutex); +} +EXPORT_SYMBOL_GPL(cscfg_deactivate_config); + +/** + * cscfg_csdev_enable_active_config - Enable matching active configuration for device. + * + * Enables the configuration selected by @cfg_hash if the configuration is supported + * on the device and has been activated. + * + * If active and supported the CoreSight device @csdev will be programmed with the + * configuration, using @preset parameters. + * + * Should be called before driver hardware enable for the requested device, prior to + * programming and enabling the physical hardware. + * + * @csdev: CoreSight device to program. + * @cfg_hash: Selector for the configuration. + * @preset: Preset parameter values to use, 0 for current / default values. + */ +int cscfg_csdev_enable_active_config(struct coresight_device *csdev, + unsigned long cfg_hash, int preset) +{ + struct cscfg_config_csdev *config_csdev_active = NULL, *config_csdev_item; + const struct cscfg_config_desc *config_desc; + unsigned long flags; + int err = 0; + + /* quickly check global count */ + if (!atomic_read(&cscfg_mgr->sys_active_cnt)) + return 0; + + /* + * Look for matching configuration - set the active configuration + * context if found. + */ + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + list_for_each_entry(config_csdev_item, &csdev->config_csdev_list, node) { + config_desc = config_csdev_item->config_desc; + if ((atomic_read(&config_desc->active_cnt)) && + ((unsigned long)config_desc->event_ea->var == cfg_hash)) { + config_csdev_active = config_csdev_item; + csdev->active_cscfg_ctxt = (void *)config_csdev_active; + break; + } + } + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); + + /* + * If found, attempt to enable + */ + if (config_csdev_active) { + /* + * Call the generic routine that will program up the internal + * driver structures prior to programming up the hardware. + * This routine takes the driver spinlock saved in the configs. + */ + err = cscfg_csdev_enable_config(config_csdev_active, preset); + if (!err) { + /* + * Successful programming. Check the active_cscfg_ctxt + * pointer to ensure no pre-emption disabled it via + * cscfg_csdev_disable_active_config() before + * we could start. + * + * Set enabled if OK, err if not. + */ + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + if (csdev->active_cscfg_ctxt) + config_csdev_active->enabled = true; + else + err = -EBUSY; + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); + } + } + return err; +} +EXPORT_SYMBOL_GPL(cscfg_csdev_enable_active_config); + +/** + * cscfg_csdev_disable_active_config - disable an active config on the device. + * + * Disables the active configuration on the CoreSight device @csdev. + * Disable will save the values of any registers marked in the configurations + * as save on disable. + * + * Should be called after driver hardware disable for the requested device, + * after disabling the physical hardware and reading back registers. + * + * @csdev: The CoreSight device. + */ +void cscfg_csdev_disable_active_config(struct coresight_device *csdev) +{ + struct cscfg_config_csdev *config_csdev; + unsigned long flags; + + /* + * Check if we have an active config, and that it was successfully enabled. + * If it was not enabled, we have no work to do, otherwise mark as disabled. + * Clear the active config pointer. + */ + spin_lock_irqsave(&csdev->cscfg_csdev_lock, flags); + config_csdev = (struct cscfg_config_csdev *)csdev->active_cscfg_ctxt; + if (config_csdev) { + if (!config_csdev->enabled) + config_csdev = NULL; + else + config_csdev->enabled = false; + } + csdev->active_cscfg_ctxt = NULL; + spin_unlock_irqrestore(&csdev->cscfg_csdev_lock, flags); + + /* true if there was an enabled active config */ + if (config_csdev) + cscfg_csdev_disable_config(config_csdev); +} +EXPORT_SYMBOL_GPL(cscfg_csdev_disable_active_config); + /* Initialise system configuration management device. */ struct device *cscfg_device(void) @@ -536,6 +750,7 @@ int __init cscfg_init(void) INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list); INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list); INIT_LIST_HEAD(&cscfg_mgr->config_desc_list); + atomic_set(&cscfg_mgr->sys_active_cnt, 0); dev_info(cscfg_device(), "CoreSight Configuration manager initialised"); return 0; diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 5bcae3b374c6..a52775890670 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -24,12 +24,14 @@ * @csdev_desc_list: List of coresight devices registered with the configuration manager. * @feat_desc_list: List of feature descriptors to load into registered devices. * @config_desc_list: List of system configuration descriptors to load into registered devices. + * @sys_active_cnt: Total number of active config descriptor references. */ struct cscfg_manager { struct device dev; struct list_head csdev_desc_list; struct list_head feat_desc_list; struct list_head config_desc_list; + atomic_t sys_active_cnt; }; /* get reference to dev in cscfg_manager */ @@ -61,5 +63,11 @@ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, int cscfg_register_csdev(struct coresight_device *csdev, u32 match_flags, struct cscfg_csdev_feat_ops *ops); void cscfg_unregister_csdev(struct coresight_device *csdev); +int cscfg_activate_config(unsigned long cfg_hash); +void cscfg_deactivate_config(unsigned long cfg_hash); +void cscfg_csdev_reset_feats(struct coresight_device *csdev); +int cscfg_csdev_enable_active_config(struct coresight_device *csdev, + unsigned long cfg_hash, int preset); +void cscfg_csdev_disable_active_config(struct coresight_device *csdev); #endif /* CORESIGHT_SYSCFG_H */ diff --git a/include/linux/coresight.h b/include/linux/coresight.h index 16544ae2b532..93a2922b7653 100644 --- a/include/linux/coresight.h +++ b/include/linux/coresight.h @@ -223,6 +223,7 @@ struct coresight_sysfs_link { * @feature_csdev_list: List of complex feature programming added to the device. * @config_csdev_list: List of system configurations added to the device. * @cscfg_csdev_lock: Protect the lists of configurations and features. + * @active_cscfg_ctxt: Context information for current active system configuration. */ struct coresight_device { struct coresight_platform_data *pdata; @@ -248,6 +249,7 @@ struct coresight_device { struct list_head feature_csdev_list; struct list_head config_csdev_list; spinlock_t cscfg_csdev_lock; + void *active_cscfg_ctxt; }; /* -- cgit v1.2.3 From a0114b4740dd739df97d09db7c9bfc11579fc515 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:17 -0600 Subject: coresight: etm-perf: Update to activate selected configuration Add calls to activate the selected configuration as perf starts and stops the tracing session. Link: https://lore.kernel.org/r/20210723165444.1048-7-mike.leach@linaro.org Reviewed-by: Suzuki K Poulose Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-7-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-etm-perf.c | 14 +++++++++++++- drivers/hwtracing/coresight/coresight-etm-perf.h | 2 ++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c index e42ab919ddc3..8ebd728d3a80 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.c +++ b/drivers/hwtracing/coresight/coresight-etm-perf.c @@ -215,6 +215,10 @@ static void free_event_data(struct work_struct *work) /* Free the sink buffers, if there are any */ free_sink_buffer(event_data); + /* clear any configuration we were using */ + if (event_data->cfg_hash) + cscfg_deactivate_config(event_data->cfg_hash); + for_each_cpu(cpu, mask) { struct list_head **ppath; @@ -292,7 +296,7 @@ static bool sinks_compatible(struct coresight_device *a, static void *etm_setup_aux(struct perf_event *event, void **pages, int nr_pages, bool overwrite) { - u32 id; + u32 id, cfg_hash; int cpu = event->cpu; cpumask_t *mask; struct coresight_device *sink = NULL; @@ -310,6 +314,14 @@ static void *etm_setup_aux(struct perf_event *event, void **pages, sink = user_sink = coresight_get_sink_by_id(id); } + /* check if user wants a coresight configuration selected */ + cfg_hash = (u32)((event->attr.config2 & GENMASK_ULL(63, 32)) >> 32); + if (cfg_hash) { + if (cscfg_activate_config(cfg_hash)) + goto err; + event_data->cfg_hash = cfg_hash; + } + mask = &event_data->mask; /* diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.h b/drivers/hwtracing/coresight/coresight-etm-perf.h index ba617fe2217e..468f7799ab4f 100644 --- a/drivers/hwtracing/coresight/coresight-etm-perf.h +++ b/drivers/hwtracing/coresight/coresight-etm-perf.h @@ -49,12 +49,14 @@ struct etm_filters { * @work: Handle to free allocated memory outside IRQ context. * @mask: Hold the CPU(s) this event was set for. * @snk_config: The sink configuration. + * @cfg_hash: The hash id of any coresight config selected. * @path: An array of path, each slot for one CPU. */ struct etm_event_data { struct work_struct work; cpumask_t mask; void *snk_config; + u32 cfg_hash; struct list_head * __percpu *path; }; -- cgit v1.2.3 From 810ac401db1fe432020d7936a199591000de8279 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:18 -0600 Subject: coresight: etm4x: Add complex configuration handlers to etmv4 Adds in handlers to allow the ETMv4 to use the complex configuration support. Features and configurations can be loaded and selected in the device. Link: https://lore.kernel.org/r/20210723165444.1048-8-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-8-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Makefile | 3 +- drivers/hwtracing/coresight/coresight-etm4x-cfg.c | 182 +++++++++++++++++++++ drivers/hwtracing/coresight/coresight-etm4x-cfg.h | 15 ++ drivers/hwtracing/coresight/coresight-etm4x-core.c | 38 ++++- .../hwtracing/coresight/coresight-etm4x-sysfs.c | 3 + 5 files changed, 238 insertions(+), 3 deletions(-) create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.c create mode 100644 drivers/hwtracing/coresight/coresight-etm4x-cfg.h diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 63ecfc3cf66d..9420d33b23ac 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -16,7 +16,8 @@ obj-$(CONFIG_CORESIGHT_SOURCE_ETM3X) += coresight-etm3x.o coresight-etm3x-y := coresight-etm3x-core.o coresight-etm-cp14.o \ coresight-etm3x-sysfs.o obj-$(CONFIG_CORESIGHT_SOURCE_ETM4X) += coresight-etm4x.o -coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o +coresight-etm4x-y := coresight-etm4x-core.o coresight-etm4x-sysfs.o \ + coresight-etm4x-cfg.o obj-$(CONFIG_CORESIGHT_STM) += coresight-stm.o obj-$(CONFIG_CORESIGHT_CPU_DEBUG) += coresight-cpu-debug.o obj-$(CONFIG_CORESIGHT_CATU) += coresight-catu.o diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c new file mode 100644 index 000000000000..d2ea903231b2 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach + */ + +#include "coresight-etm4x.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-priv.h" +#include "coresight-syscfg.h" + +/* defines to associate register IDs with driver data locations */ +#define CHECKREG(cval, elem) \ + { \ + if (offset == cval) { \ + reg_csdev->driver_regval = &drvcfg->elem; \ + err = 0; \ + break; \ + } \ + } + +#define CHECKREGIDX(cval, elem, off_idx, mask) \ + { \ + if (mask == cval) { \ + reg_csdev->driver_regval = &drvcfg->elem[off_idx]; \ + err = 0; \ + break; \ + } \ + } + +/** + * etm4_cfg_map_reg_offset - validate and map the register offset into a + * location in the driver config struct. + * + * Limits the number of registers that can be accessed and programmed in + * features, to those which are used to control the trace capture parameters. + * + * Omits or limits access to those which the driver must use exclusively. + * + * Invalid offsets will result in fail code return and feature load failure. + * + * @drvdata: driver data to map into. + * @reg: register to map. + * @offset: device offset for the register + */ +static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata, + struct cscfg_regval_csdev *reg_csdev, u32 offset) +{ + int err = -EINVAL, idx; + struct etmv4_config *drvcfg = &drvdata->config; + u32 off_mask; + + if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) || + ((offset >= TRCSEQRSTEVR) && (offset <= TRCEXTINSELR)) || + ((offset >= TRCCIDCCTLR0) && (offset <= TRCVMIDCCTLR1))) { + do { + CHECKREG(TRCEVENTCTL0R, eventctrl0); + CHECKREG(TRCEVENTCTL1R, eventctrl1); + CHECKREG(TRCSTALLCTLR, stall_ctrl); + CHECKREG(TRCTSCTLR, ts_ctrl); + CHECKREG(TRCSYNCPR, syncfreq); + CHECKREG(TRCCCCTLR, ccctlr); + CHECKREG(TRCBBCTLR, bb_ctrl); + CHECKREG(TRCVICTLR, vinst_ctrl); + CHECKREG(TRCVIIECTLR, viiectlr); + CHECKREG(TRCVISSCTLR, vissctlr); + CHECKREG(TRCVIPCSSCTLR, vipcssctlr); + CHECKREG(TRCSEQRSTEVR, seq_rst); + CHECKREG(TRCSEQSTR, seq_state); + CHECKREG(TRCEXTINSELR, ext_inp); + CHECKREG(TRCCIDCCTLR0, ctxid_mask0); + CHECKREG(TRCCIDCCTLR1, ctxid_mask1); + CHECKREG(TRCVMIDCCTLR0, vmid_mask0); + CHECKREG(TRCVMIDCCTLR1, vmid_mask1); + } while (0); + } else if ((offset & GENMASK(11, 4)) == TRCSEQEVRn(0)) { + /* sequencer state control registers */ + idx = (offset & GENMASK(3, 0)) / 4; + if (idx < ETM_MAX_SEQ_STATES) { + reg_csdev->driver_regval = &drvcfg->seq_ctrl[idx]; + err = 0; + } + } else if ((offset >= TRCSSCCRn(0)) && (offset <= TRCSSPCICRn(7))) { + /* 32 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(4, 0)) / 4; + off_mask = (offset & GENMASK(11, 5)); + do { + CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask); + CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask); + CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask); + } while (0); + } else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) { + /* 64 bit, 8 off indexed register sets */ + idx = (offset & GENMASK(5, 0)) / 8; + off_mask = (offset & GENMASK(11, 6)); + do { + CHECKREGIDX(TRCCIDCVRn(0), ctxid_pid, idx, off_mask); + CHECKREGIDX(TRCVMIDCVRn(0), vmid_val, idx, off_mask); + } while (0); + } else if ((offset >= TRCRSCTLRn(2)) && + (offset <= TRCRSCTLRn((ETM_MAX_RES_SEL - 1)))) { + /* 32 bit resource selection regs, 32 off, skip fixed 0,1 */ + idx = (offset & GENMASK(6, 0)) / 4; + if (idx < ETM_MAX_RES_SEL) { + reg_csdev->driver_regval = &drvcfg->res_ctrl[idx]; + err = 0; + } + } else if ((offset >= TRCACVRn(0)) && + (offset <= TRCACATRn((ETM_MAX_SINGLE_ADDR_CMP - 1)))) { + /* 64 bit addr cmp regs, 16 off */ + idx = (offset & GENMASK(6, 0)) / 8; + off_mask = offset & GENMASK(11, 7); + do { + CHECKREGIDX(TRCACVRn(0), addr_val, idx, off_mask); + CHECKREGIDX(TRCACATRn(0), addr_acc, idx, off_mask); + } while (0); + } else if ((offset >= TRCCNTRLDVRn(0)) && + (offset <= TRCCNTVRn((ETMv4_MAX_CNTR - 1)))) { + /* 32 bit counter regs, 4 off (ETMv4_MAX_CNTR - 1) */ + idx = (offset & GENMASK(3, 0)) / 4; + off_mask = offset & GENMASK(11, 4); + do { + CHECKREGIDX(TRCCNTRLDVRn(0), cntrldvr, idx, off_mask); + CHECKREGIDX(TRCCNTCTLRn(0), cntr_ctrl, idx, off_mask); + CHECKREGIDX(TRCCNTVRn(0), cntr_val, idx, off_mask); + } while (0); + } + return err; +} + +/** + * etm4_cfg_load_feature - load a feature into a device instance. + * + * @csdev: An ETMv4 CoreSight device. + * @feat: The feature to be loaded. + * + * The function will load a feature instance into the device, checking that + * the register definitions are valid for the device. + * + * Parameter and register definitions will be converted into internal + * structures that are used to set the values in the driver when the + * feature is enabled for the device. + * + * The feature spinlock pointer is initialised to the same spinlock + * that the driver uses to protect the internal register values. + */ +static int etm4_cfg_load_feature(struct coresight_device *csdev, + struct cscfg_feature_csdev *feat_csdev) +{ + struct device *dev = csdev->dev.parent; + struct etmv4_drvdata *drvdata = dev_get_drvdata(dev); + const struct cscfg_feature_desc *feat_desc = feat_csdev->feat_desc; + u32 offset; + int i = 0, err = 0; + + /* + * essential we set the device spinlock - this is used in the generic + * programming routines when copying values into the drvdata structures + * via the pointers setup in etm4_cfg_map_reg_offset(). + */ + feat_csdev->drv_spinlock = &drvdata->spinlock; + + /* process the register descriptions */ + for (i = 0; i < feat_csdev->nr_regs && !err; i++) { + offset = feat_desc->regs_desc[i].offset; + err = etm4_cfg_map_reg_offset(drvdata, &feat_csdev->regs_csdev[i], offset); + } + return err; +} + +/* match information when loading configurations */ +#define CS_CFG_ETM4_MATCH_FLAGS (CS_CFG_MATCH_CLASS_SRC_ALL | \ + CS_CFG_MATCH_CLASS_SRC_ETM4) + +int etm4_cscfg_register(struct coresight_device *csdev) +{ + struct cscfg_csdev_feat_ops ops; + + ops.load_feat = &etm4_cfg_load_feature; + + return cscfg_register_csdev(csdev, CS_CFG_ETM4_MATCH_FLAGS, &ops); +} diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h new file mode 100644 index 000000000000..a204ad9a4792 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. + */ + +#ifndef _CORESIGHT_ETM4X_CFG_H +#define _CORESIGHT_ETM4X_CFG_H + +#include "coresight-config.h" +#include "coresight-etm4x.h" + +/* ETMv4 specific config functions */ +int etm4_cscfg_register(struct coresight_device *csdev); + +#endif /* CORESIGHT_ETM4X_CFG_H */ diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c index da27cd4a3c38..e24252eaf8e4 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-core.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c @@ -39,6 +39,8 @@ #include "coresight-etm4x.h" #include "coresight-etm-perf.h" +#include "coresight-etm4x-cfg.h" +#include "coresight-syscfg.h" static int boot_enable; module_param(boot_enable, int, 0444); @@ -561,12 +563,15 @@ out: return ret; } -static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, +static int etm4_parse_event_config(struct coresight_device *csdev, struct perf_event *event) { int ret = 0; + struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); struct etmv4_config *config = &drvdata->config; struct perf_event_attr *attr = &event->attr; + unsigned long cfg_hash; + int preset; /* Clear configuration from previous run */ memset(config, 0, sizeof(struct etmv4_config)); @@ -632,6 +637,20 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata, /* bit[12], Return stack enable bit */ config->cfg |= BIT(12); + /* + * Set any selected configuration and preset. + * + * This extracts the values of PMU_FORMAT_ATTR(configid) and PMU_FORMAT_ATTR(preset) + * in the perf attributes defined in coresight-etm-perf.c. + * configid uses bits 63:32 of attr->config2, preset uses bits 3:0 of attr->config. + * A zero configid means no configuration active, preset = 0 means no preset selected. + */ + if (attr->config2 & GENMASK_ULL(63, 32)) { + cfg_hash = (u32)(attr->config2 >> 32); + preset = attr->config & 0xF; + ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset); + } + out: return ret; } @@ -648,7 +667,7 @@ static int etm4_enable_perf(struct coresight_device *csdev, } /* Configure the tracer based on the session's specifics */ - ret = etm4_parse_event_config(drvdata, event); + ret = etm4_parse_event_config(csdev, event); if (ret) goto out; /* And enable it */ @@ -794,11 +813,18 @@ static int etm4_disable_perf(struct coresight_device *csdev, u32 control; struct etm_filters *filters = event->hw.addr_filters; struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); + struct perf_event_attr *attr = &event->attr; if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) return -EINVAL; etm4_disable_hw(drvdata); + /* + * The config_id occupies bits 63:32 of the config2 perf event attr + * field. If this is non-zero then we will have enabled a config. + */ + if (attr->config2 & GENMASK_ULL(63, 32)) + cscfg_csdev_disable_active_config(csdev); /* * Check if the start/stop logic was active when the unit was stopped. @@ -1939,6 +1965,13 @@ static int etm4_probe(struct device *dev, void __iomem *base, u32 etm_pid) return ret; } + /* register with config infrastructure & load any current features */ + ret = etm4_cscfg_register(drvdata->csdev); + if (ret) { + coresight_unregister(drvdata->csdev); + return ret; + } + etmdrvdata[drvdata->cpu] = drvdata; dev_info(&drvdata->csdev->dev, "CPU%d: %s v%d.%d initialized\n", @@ -2025,6 +2058,7 @@ static int __exit etm4_remove_dev(struct etmv4_drvdata *drvdata) cpus_read_unlock(); + cscfg_unregister_csdev(drvdata->csdev); coresight_unregister(drvdata->csdev); return 0; diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c index 007bad9e7ad8..a0640fa5c55b 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c +++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c @@ -9,6 +9,7 @@ #include #include "coresight-etm4x.h" #include "coresight-priv.h" +#include "coresight-syscfg.h" static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude) { @@ -269,6 +270,8 @@ static ssize_t reset_store(struct device *dev, spin_unlock(&drvdata->spinlock); + cscfg_csdev_reset_feats(to_coresight_device(dev)); + return size; } static DEVICE_ATTR_WO(reset); -- cgit v1.2.3 From 7fdc9bb2ce113c5318fdacbb717897fede81949d Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:19 -0600 Subject: coresight: config: Add preloaded configurations Preload set of configurations. This patch creates a small set of preloaded configurations and features that are available immediately after coresight has been initialised. The current set provides a strobing feature for ETMv4, that creates a periodic sampling of trace by switching trace generation on and off using counters in the ETM. A configuration called "autofdo" is also provided that uses the 'strobing' feature and provides a couple of preset values, selectable on the perf command line. Link: https://lore.kernel.org/r/20210723165444.1048-9-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-9-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Makefile | 3 +- drivers/hwtracing/coresight/coresight-cfg-afdo.c | 153 +++++++++++++++++++++ .../hwtracing/coresight/coresight-cfg-preload.c | 31 +++++ .../hwtracing/coresight/coresight-cfg-preload.h | 13 ++ drivers/hwtracing/coresight/coresight-etm4x-cfg.h | 15 ++ drivers/hwtracing/coresight/coresight-syscfg.c | 9 ++ drivers/hwtracing/coresight/coresight-syscfg.h | 1 + 7 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-cfg-afdo.c create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.c create mode 100644 drivers/hwtracing/coresight/coresight-cfg-preload.h diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index 9420d33b23ac..ad44f0fe3069 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -4,7 +4,8 @@ # obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ - coresight-sysfs.o coresight-syscfg.o coresight-config.o + coresight-sysfs.o coresight-syscfg.o coresight-config.o \ + coresight-cfg-preload.o coresight-cfg-afdo.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-cfg-afdo.c b/drivers/hwtracing/coresight/coresight-cfg-afdo.c new file mode 100644 index 000000000000..84b31184252b --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-afdo.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach + */ + +#include "coresight-config.h" + +/* ETMv4 includes and features */ +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) +#include "coresight-etm4x-cfg.h" + +/* preload configurations and features */ + +/* preload in features for ETMv4 */ + +/* strobe feature */ +static struct cscfg_parameter_desc strobe_params[] = { + { + .name = "window", + .value = 5000, + }, + { + .name = "period", + .value = 10000, + }, +}; + +static struct cscfg_regval_desc strobe_regs[] = { + /* resource selectors */ + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCRSCTLRn(2), + .hw_info = ETM4_CFG_RES_SEL, + .val32 = 0x20001, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCRSCTLRn(3), + .hw_info = ETM4_CFG_RES_SEQ, + .val32 = 0x20002, + }, + /* strobe window counter 0 - reload from param 0 */ + { + .type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE, + .offset = TRCCNTVRn(0), + .hw_info = ETM4_CFG_RES_CTR, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM, + .offset = TRCCNTRLDVRn(0), + .hw_info = ETM4_CFG_RES_CTR, + .val32 = 0, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCCNTCTLRn(0), + .hw_info = ETM4_CFG_RES_CTR, + .val32 = 0x10001, + }, + /* strobe period counter 1 - reload from param 1 */ + { + .type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_SAVE, + .offset = TRCCNTVRn(1), + .hw_info = ETM4_CFG_RES_CTR, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE | CS_CFG_REG_TYPE_VAL_PARAM, + .offset = TRCCNTRLDVRn(1), + .hw_info = ETM4_CFG_RES_CTR, + .val32 = 1, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCCNTCTLRn(1), + .hw_info = ETM4_CFG_RES_CTR, + .val32 = 0x8102, + }, + /* sequencer */ + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCSEQEVRn(0), + .hw_info = ETM4_CFG_RES_SEQ, + .val32 = 0x0081, + }, + { + .type = CS_CFG_REG_TYPE_RESOURCE, + .offset = TRCSEQEVRn(1), + .hw_info = ETM4_CFG_RES_SEQ, + .val32 = 0x0000, + }, + /* view-inst */ + { + .type = CS_CFG_REG_TYPE_STD | CS_CFG_REG_TYPE_VAL_MASK, + .offset = TRCVICTLR, + .val32 = 0x0003, + .mask32 = 0x0003, + }, + /* end of regs */ +}; + +struct cscfg_feature_desc strobe_etm4x = { + .name = "strobing", + .description = "Generate periodic trace capture windows.\n" + "parameter \'window\': a number of CPU cycles (W)\n" + "parameter \'period\': trace enabled for W cycles every period x W cycles\n", + .match_flags = CS_CFG_MATCH_CLASS_SRC_ETM4, + .nr_params = ARRAY_SIZE(strobe_params), + .params_desc = strobe_params, + .nr_regs = ARRAY_SIZE(strobe_regs), + .regs_desc = strobe_regs, +}; + +/* create an autofdo configuration */ + +/* we will provide 9 sets of preset parameter values */ +#define AFDO_NR_PRESETS 9 +/* the total number of parameters in used features */ +#define AFDO_NR_PARAMS ARRAY_SIZE(strobe_params) + +static const char *afdo_ref_names[] = { + "strobing", +}; + +/* + * set of presets leaves strobing window constant while varying period to allow + * experimentation with mark / space ratios for various workloads + */ +static u64 afdo_presets[AFDO_NR_PRESETS][AFDO_NR_PARAMS] = { + { 5000, 2 }, + { 5000, 4 }, + { 5000, 8 }, + { 5000, 16 }, + { 5000, 64 }, + { 5000, 128 }, + { 5000, 512 }, + { 5000, 1024 }, + { 5000, 4096 }, +}; + +struct cscfg_config_desc afdo_etm4x = { + .name = "autofdo", + .description = "Setup ETMs with strobing for autofdo\n" + "Supplied presets allow experimentation with mark-space ratio for various loads\n", + .nr_feat_refs = ARRAY_SIZE(afdo_ref_names), + .feat_ref_names = afdo_ref_names, + .nr_presets = AFDO_NR_PRESETS, + .nr_total_params = AFDO_NR_PARAMS, + .presets = &afdo_presets[0][0], +}; + +/* end of ETM4x configurations */ +#endif /* IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) */ diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.c b/drivers/hwtracing/coresight/coresight-cfg-preload.c new file mode 100644 index 000000000000..751af3710d56 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach + */ + +#include "coresight-cfg-preload.h" +#include "coresight-config.h" +#include "coresight-syscfg.h" + +/* Basic features and configurations pre-loaded on initialisation */ + +static struct cscfg_feature_desc *preload_feats[] = { +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) + &strobe_etm4x, +#endif + NULL +}; + +static struct cscfg_config_desc *preload_cfgs[] = { +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) + &afdo_etm4x, +#endif + NULL +}; + +/* preload called on initialisation */ +int cscfg_preload(void) +{ + return cscfg_load_config_sets(preload_cfgs, preload_feats); +} diff --git a/drivers/hwtracing/coresight/coresight-cfg-preload.h b/drivers/hwtracing/coresight/coresight-cfg-preload.h new file mode 100644 index 000000000000..21299e175477 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-cfg-preload.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright(C) 2020 Linaro Limited. All rights reserved. + * Author: Mike Leach + */ + +/* declare preloaded configurations and features */ + +/* from coresight-cfg-afdo.c - etm 4x features */ +#if IS_ENABLED(CONFIG_CORESIGHT_SOURCE_ETM4X) +extern struct cscfg_feature_desc strobe_etm4x; +extern struct cscfg_config_desc afdo_etm4x; +#endif diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h index a204ad9a4792..32dab34c1dac 100644 --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.h +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.h @@ -9,6 +9,21 @@ #include "coresight-config.h" #include "coresight-etm4x.h" +/* ETMv4 specific config defines */ + +/* resource IDs */ + +#define ETM4_CFG_RES_CTR 0x001 +#define ETM4_CFG_RES_CMP 0x002 +#define ETM4_CFG_RES_CMP_PAIR0 0x003 +#define ETM4_CFG_RES_CMP_PAIR1 0x004 +#define ETM4_CFG_RES_SEL 0x005 +#define ETM4_CFG_RES_SEL_PAIR0 0x006 +#define ETM4_CFG_RES_SEL_PAIR1 0x007 +#define ETM4_CFG_RES_SEQ 0x008 +#define ETM4_CFG_RES_TS 0x009 +#define ETM4_CFG_RES_MASK 0x00F + /* ETMv4 specific config functions */ int etm4_cscfg_register(struct coresight_device *csdev); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index 795dba576fea..c0f764d85f20 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -752,8 +752,17 @@ int __init cscfg_init(void) INIT_LIST_HEAD(&cscfg_mgr->config_desc_list); atomic_set(&cscfg_mgr->sys_active_cnt, 0); + /* preload built-in configurations */ + err = cscfg_preload(); + if (err) + goto exit_err; + dev_info(cscfg_device(), "CoreSight Configuration manager initialised"); return 0; + +exit_err: + cscfg_clear_device(); + return err; } void cscfg_exit(void) diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index a52775890670..7bb8c8e497ba 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -56,6 +56,7 @@ struct cscfg_registered_csdev { /* internal core operations for cscfg */ int __init cscfg_init(void); void cscfg_exit(void); +int cscfg_preload(void); /* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- cgit v1.2.3 From a13d5a246aca17c44514be9afa20b34443182356 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:20 -0600 Subject: coresight: syscfg: Add initial configfs support Adds configfs subsystem and attributes to the configuration manager to enable the listing of loaded configurations and features. The default values of feature parameters can be accessed and altered from these attributes to affect all installed devices using the feature. Link: https://lore.kernel.org/r/20210723165444.1048-10-mike.leach@linaro.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-10-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Kconfig | 1 + drivers/hwtracing/coresight/Makefile | 3 +- .../coresight/coresight-syscfg-configfs.c | 396 +++++++++++++++++++++ .../coresight/coresight-syscfg-configfs.h | 45 +++ drivers/hwtracing/coresight/coresight-syscfg.c | 76 ++++ drivers/hwtracing/coresight/coresight-syscfg.h | 7 + 6 files changed, 527 insertions(+), 1 deletion(-) create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.c create mode 100644 drivers/hwtracing/coresight/coresight-syscfg-configfs.h diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 84530fd80998..f026e5c0e777 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -8,6 +8,7 @@ menuconfig CORESIGHT depends on OF || ACPI select ARM_AMBA select PERF_EVENTS + select CONFIGFS_FS help This framework provides a kernel interface for the CoreSight debug and trace drivers to register themselves with. It's intended to build diff --git a/drivers/hwtracing/coresight/Makefile b/drivers/hwtracing/coresight/Makefile index ad44f0fe3069..b6c4a48140ec 100644 --- a/drivers/hwtracing/coresight/Makefile +++ b/drivers/hwtracing/coresight/Makefile @@ -5,7 +5,8 @@ obj-$(CONFIG_CORESIGHT) += coresight.o coresight-y := coresight-core.o coresight-etm-perf.o coresight-platform.o \ coresight-sysfs.o coresight-syscfg.o coresight-config.o \ - coresight-cfg-preload.o coresight-cfg-afdo.o + coresight-cfg-preload.o coresight-cfg-afdo.o \ + coresight-syscfg-configfs.o obj-$(CONFIG_CORESIGHT_LINK_AND_SINK_TMC) += coresight-tmc.o coresight-tmc-y := coresight-tmc-core.o coresight-tmc-etf.o \ coresight-tmc-etr.o diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.c b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c new file mode 100644 index 000000000000..c547816b9000 --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.c @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 Linaro Limited, All rights reserved. + * Author: Mike Leach + */ + +#include + +#include "coresight-syscfg-configfs.h" + +/* create a default ci_type. */ +static inline struct config_item_type *cscfg_create_ci_type(void) +{ + struct config_item_type *ci_type; + + ci_type = devm_kzalloc(cscfg_device(), sizeof(*ci_type), GFP_KERNEL); + if (ci_type) + ci_type->ct_owner = THIS_MODULE; + + return ci_type; +} + +/* configurations sub-group */ + +/* attributes for the config view group */ +static ssize_t cscfg_cfg_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = container_of(to_config_group(item), + struct cscfg_fs_config, group); + + return scnprintf(page, PAGE_SIZE, "%s", fs_config->config_desc->description); +} +CONFIGFS_ATTR_RO(cscfg_cfg_, description); + +static ssize_t cscfg_cfg_feature_refs_show(struct config_item *item, char *page) +{ + struct cscfg_fs_config *fs_config = container_of(to_config_group(item), + struct cscfg_fs_config, group); + const struct cscfg_config_desc *config_desc = fs_config->config_desc; + ssize_t ch_used = 0; + int i; + + for (i = 0; i < config_desc->nr_feat_refs; i++) + ch_used += scnprintf(page + ch_used, PAGE_SIZE - ch_used, + "%s\n", config_desc->feat_ref_names[i]); + return ch_used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, feature_refs); + +/* list preset values in order of features and params */ +static ssize_t cscfg_cfg_values_show(struct config_item *item, char *page) +{ + const struct cscfg_feature_desc *feat_desc; + const struct cscfg_config_desc *config_desc; + struct cscfg_fs_preset *fs_preset; + int i, j, val_idx, preset_idx; + ssize_t used = 0; + + fs_preset = container_of(to_config_group(item), struct cscfg_fs_preset, group); + config_desc = fs_preset->config_desc; + + if (!config_desc->nr_presets) + return 0; + + preset_idx = fs_preset->preset_num - 1; + + /* start index on the correct array line */ + val_idx = config_desc->nr_total_params * preset_idx; + + /* + * A set of presets is the sum of all params in used features, + * in order of declaration of features and params in the features + */ + for (i = 0; i < config_desc->nr_feat_refs; i++) { + feat_desc = cscfg_get_named_feat_desc(config_desc->feat_ref_names[i]); + for (j = 0; j < feat_desc->nr_params; j++) { + used += scnprintf(page + used, PAGE_SIZE - used, + "%s.%s = 0x%llx ", + feat_desc->name, + feat_desc->params_desc[j].name, + config_desc->presets[val_idx++]); + } + } + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + + return used; +} +CONFIGFS_ATTR_RO(cscfg_cfg_, values); + +static struct configfs_attribute *cscfg_config_view_attrs[] = { + &cscfg_cfg_attr_description, + &cscfg_cfg_attr_feature_refs, + NULL, +}; + +static struct config_item_type cscfg_config_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_config_view_attrs, +}; + +static struct configfs_attribute *cscfg_config_preset_attrs[] = { + &cscfg_cfg_attr_values, + NULL, +}; + +static struct config_item_type cscfg_config_preset_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_config_preset_attrs, +}; + +static int cscfg_add_preset_groups(struct cscfg_fs_config *cfg_view) +{ + int preset_num; + struct cscfg_fs_preset *cfg_fs_preset; + struct cscfg_config_desc *config_desc = cfg_view->config_desc; + char name[CONFIGFS_ITEM_NAME_LEN]; + + if (!config_desc->nr_presets) + return 0; + + for (preset_num = 1; preset_num <= config_desc->nr_presets; preset_num++) { + cfg_fs_preset = devm_kzalloc(cscfg_device(), + sizeof(struct cscfg_fs_preset), GFP_KERNEL); + + if (!cfg_fs_preset) + return -ENOMEM; + + snprintf(name, CONFIGFS_ITEM_NAME_LEN, "preset%d", preset_num); + cfg_fs_preset->preset_num = preset_num; + cfg_fs_preset->config_desc = cfg_view->config_desc; + config_group_init_type_name(&cfg_fs_preset->group, name, + &cscfg_config_preset_type); + configfs_add_default_group(&cfg_fs_preset->group, &cfg_view->group); + } + return 0; +} + +static struct config_group *cscfg_create_config_group(struct cscfg_config_desc *config_desc) +{ + struct cscfg_fs_config *cfg_view; + struct device *dev = cscfg_device(); + int err; + + if (!dev) + return ERR_PTR(-EINVAL); + + cfg_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_config), GFP_KERNEL); + if (!cfg_view) + return ERR_PTR(-ENOMEM); + + cfg_view->config_desc = config_desc; + config_group_init_type_name(&cfg_view->group, config_desc->name, &cscfg_config_view_type); + + /* add in a preset dir for each preset */ + err = cscfg_add_preset_groups(cfg_view); + if (err) + return ERR_PTR(err); + + return &cfg_view->group; +} + +/* attributes for features view */ + +static ssize_t cscfg_feat_description_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item), + struct cscfg_fs_feature, group); + + return scnprintf(page, PAGE_SIZE, "%s", fs_feat->feat_desc->description); +} +CONFIGFS_ATTR_RO(cscfg_feat_, description); + +static ssize_t cscfg_feat_matches_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item), + struct cscfg_fs_feature, group); + u32 match_flags = fs_feat->feat_desc->match_flags; + int used = 0; + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ALL) + used = scnprintf(page, PAGE_SIZE, "SRC_ALL "); + + if (match_flags & CS_CFG_MATCH_CLASS_SRC_ETM4) + used += scnprintf(page + used, PAGE_SIZE - used, "SRC_ETMV4 "); + + used += scnprintf(page + used, PAGE_SIZE - used, "\n"); + return used; +} +CONFIGFS_ATTR_RO(cscfg_feat_, matches); + +static ssize_t cscfg_feat_nr_params_show(struct config_item *item, char *page) +{ + struct cscfg_fs_feature *fs_feat = container_of(to_config_group(item), + struct cscfg_fs_feature, group); + + return scnprintf(page, PAGE_SIZE, "%d\n", fs_feat->feat_desc->nr_params); +} +CONFIGFS_ATTR_RO(cscfg_feat_, nr_params); + +/* base feature desc attrib structures */ +static struct configfs_attribute *cscfg_feature_view_attrs[] = { + &cscfg_feat_attr_description, + &cscfg_feat_attr_matches, + &cscfg_feat_attr_nr_params, + NULL, +}; + +static struct config_item_type cscfg_feature_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_feature_view_attrs, +}; + +static ssize_t cscfg_param_value_show(struct config_item *item, char *page) +{ + struct cscfg_fs_param *param_item = container_of(to_config_group(item), + struct cscfg_fs_param, group); + u64 value = param_item->feat_desc->params_desc[param_item->param_idx].value; + + return scnprintf(page, PAGE_SIZE, "0x%llx\n", value); +} + +static ssize_t cscfg_param_value_store(struct config_item *item, + const char *page, size_t size) +{ + struct cscfg_fs_param *param_item = container_of(to_config_group(item), + struct cscfg_fs_param, group); + struct cscfg_feature_desc *feat_desc = param_item->feat_desc; + int param_idx = param_item->param_idx; + u64 value; + int err; + + err = kstrtoull(page, 0, &value); + if (!err) + err = cscfg_update_feat_param_val(feat_desc, param_idx, value); + + return err ? err : size; +} +CONFIGFS_ATTR(cscfg_param_, value); + +static struct configfs_attribute *cscfg_param_view_attrs[] = { + &cscfg_param_attr_value, + NULL, +}; + +static struct config_item_type cscfg_param_view_type = { + .ct_owner = THIS_MODULE, + .ct_attrs = cscfg_param_view_attrs, +}; + +/* + * configfs has far less functionality provided to add attributes dynamically than sysfs, + * and the show and store fns pass the enclosing config_item so the actual attribute cannot + * be determined. Therefore we add each item as a group directory, with a value attribute. + */ +static int cscfg_create_params_group_items(struct cscfg_feature_desc *feat_desc, + struct config_group *params_group) +{ + struct device *dev = cscfg_device(); + struct cscfg_fs_param *param_item; + int i; + + /* parameter items - as groups with default_value attribute */ + for (i = 0; i < feat_desc->nr_params; i++) { + param_item = devm_kzalloc(dev, sizeof(struct cscfg_fs_param), GFP_KERNEL); + if (!param_item) + return -ENOMEM; + param_item->feat_desc = feat_desc; + param_item->param_idx = i; + config_group_init_type_name(¶m_item->group, + feat_desc->params_desc[i].name, + &cscfg_param_view_type); + configfs_add_default_group(¶m_item->group, params_group); + } + return 0; +} + +static struct config_group *cscfg_create_feature_group(struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_fs_feature *feat_view; + struct config_item_type *params_group_type; + struct config_group *params_group = NULL; + struct device *dev = cscfg_device(); + int item_err; + + if (!dev) + return ERR_PTR(-EINVAL); + + feat_view = devm_kzalloc(dev, sizeof(struct cscfg_fs_feature), GFP_KERNEL); + if (!feat_view) + return ERR_PTR(-ENOMEM); + + if (feat_desc->nr_params) { + params_group = devm_kzalloc(dev, sizeof(struct config_group), GFP_KERNEL); + if (!params_group) + return ERR_PTR(-ENOMEM); + + params_group_type = cscfg_create_ci_type(); + if (!params_group_type) + return ERR_PTR(-ENOMEM); + } + + feat_view->feat_desc = feat_desc; + config_group_init_type_name(&feat_view->group, + feat_desc->name, + &cscfg_feature_view_type); + if (params_group) { + config_group_init_type_name(params_group, "params", params_group_type); + configfs_add_default_group(params_group, &feat_view->group); + item_err = cscfg_create_params_group_items(feat_desc, params_group); + if (item_err) + return ERR_PTR(item_err); + } + return &feat_view->group; +} + +static struct config_item_type cscfg_configs_type = { + .ct_owner = THIS_MODULE, +}; + +static struct config_group cscfg_configs_grp = { + .cg_item = { + .ci_namebuf = "configurations", + .ci_type = &cscfg_configs_type, + }, +}; + +/* add configuration to configurations group */ +int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_config_group(config_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_configs_grp, new_group); + return err; +} + +static struct config_item_type cscfg_features_type = { + .ct_owner = THIS_MODULE, +}; + +static struct config_group cscfg_features_grp = { + .cg_item = { + .ci_namebuf = "features", + .ci_type = &cscfg_features_type, + }, +}; + +/* add feature to features group */ +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc) +{ + struct config_group *new_group; + int err; + + new_group = cscfg_create_feature_group(feat_desc); + if (IS_ERR(new_group)) + return PTR_ERR(new_group); + err = configfs_register_group(&cscfg_features_grp, new_group); + return err; +} + +int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr) +{ + struct configfs_subsystem *subsys; + struct config_item_type *ci_type; + + if (!cscfg_mgr) + return -EINVAL; + + ci_type = cscfg_create_ci_type(); + if (!ci_type) + return -ENOMEM; + + subsys = &cscfg_mgr->cfgfs_subsys; + config_item_set_name(&subsys->su_group.cg_item, CSCFG_FS_SUBSYS_NAME); + subsys->su_group.cg_item.ci_type = ci_type; + + config_group_init(&subsys->su_group); + mutex_init(&subsys->su_mutex); + + /* Add default groups to subsystem */ + config_group_init(&cscfg_configs_grp); + configfs_add_default_group(&cscfg_configs_grp, &subsys->su_group); + + config_group_init(&cscfg_features_grp); + configfs_add_default_group(&cscfg_features_grp, &subsys->su_group); + + return configfs_register_subsystem(subsys); +} + +void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr) +{ + configfs_unregister_subsystem(&cscfg_mgr->cfgfs_subsys); +} diff --git a/drivers/hwtracing/coresight/coresight-syscfg-configfs.h b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h new file mode 100644 index 000000000000..7d6ffe35ca4c --- /dev/null +++ b/drivers/hwtracing/coresight/coresight-syscfg-configfs.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Coresight system configuration driver - support for configfs. + */ + +#ifndef CORESIGHT_SYSCFG_CONFIGFS_H +#define CORESIGHT_SYSCFG_CONFIGFS_H + +#include +#include "coresight-syscfg.h" + +#define CSCFG_FS_SUBSYS_NAME "cs-syscfg" + +/* container for configuration view */ +struct cscfg_fs_config { + struct cscfg_config_desc *config_desc; + struct config_group group; +}; + +/* container for feature view */ +struct cscfg_fs_feature { + struct cscfg_feature_desc *feat_desc; + struct config_group group; +}; + +/* container for parameter view */ +struct cscfg_fs_param { + int param_idx; + struct cscfg_feature_desc *feat_desc; + struct config_group group; +}; + +/* container for preset view */ +struct cscfg_fs_preset { + int preset_num; + struct cscfg_config_desc *config_desc; + struct config_group group; +}; + +int cscfg_configfs_init(struct cscfg_manager *cscfg_mgr); +void cscfg_configfs_release(struct cscfg_manager *cscfg_mgr); +int cscfg_configfs_add_config(struct cscfg_config_desc *config_desc); +int cscfg_configfs_add_feature(struct cscfg_feature_desc *feat_desc); + +#endif /* CORESIGHT_SYSCFG_CONFIGFS_H */ diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c index c0f764d85f20..fc0760f55c53 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.c +++ b/drivers/hwtracing/coresight/coresight-syscfg.c @@ -9,6 +9,7 @@ #include "coresight-config.h" #include "coresight-etm-perf.h" #include "coresight-syscfg.h" +#include "coresight-syscfg-configfs.h" /* * cscfg_ API manages configurations and features for the entire coresight @@ -286,6 +287,72 @@ static int cscfg_load_config(struct cscfg_config_desc *config_desc) return 0; } +/* get a feature descriptor by name */ +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name) +{ + const struct cscfg_feature_desc *feat_desc = NULL, *feat_desc_item; + + mutex_lock(&cscfg_mutex); + + list_for_each_entry(feat_desc_item, &cscfg_mgr->feat_desc_list, item) { + if (strcmp(feat_desc_item->name, name) == 0) { + feat_desc = feat_desc_item; + break; + } + } + + mutex_unlock(&cscfg_mutex); + return feat_desc; +} + +/* called with cscfg_mutex held */ +static struct cscfg_feature_csdev * +cscfg_csdev_get_feat_from_desc(struct coresight_device *csdev, + struct cscfg_feature_desc *feat_desc) +{ + struct cscfg_feature_csdev *feat_csdev; + + list_for_each_entry(feat_csdev, &csdev->feature_csdev_list, node) { + if (feat_csdev->feat_desc == feat_desc) + return feat_csdev; + } + return NULL; +} + +int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, + int param_idx, u64 value) +{ + int err = 0; + struct cscfg_feature_csdev *feat_csdev; + struct cscfg_registered_csdev *csdev_item; + + mutex_lock(&cscfg_mutex); + + /* check if any config active & return busy */ + if (atomic_read(&cscfg_mgr->sys_active_cnt)) { + err = -EBUSY; + goto unlock_exit; + } + + /* set the value */ + if ((param_idx < 0) || (param_idx >= feat_desc->nr_params)) { + err = -EINVAL; + goto unlock_exit; + } + feat_desc->params_desc[param_idx].value = value; + + /* update loaded instances.*/ + list_for_each_entry(csdev_item, &cscfg_mgr->csdev_desc_list, item) { + feat_csdev = cscfg_csdev_get_feat_from_desc(csdev_item->csdev, feat_desc); + if (feat_csdev) + feat_csdev->params_csdev[param_idx].current_value = value; + } + +unlock_exit: + mutex_unlock(&cscfg_mutex); + return err; +} + /** * cscfg_load_config_sets - API function to load feature and config sets. * @@ -307,6 +374,8 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs, if (feat_descs) { while (feat_descs[i]) { err = cscfg_load_feat(feat_descs[i]); + if (!err) + err = cscfg_configfs_add_feature(feat_descs[i]); if (err) { pr_err("coresight-syscfg: Failed to load feature %s\n", feat_descs[i]->name); @@ -321,6 +390,8 @@ int cscfg_load_config_sets(struct cscfg_config_desc **config_descs, if (config_descs) { while (config_descs[i]) { err = cscfg_load_config(config_descs[i]); + if (!err) + err = cscfg_configfs_add_config(config_descs[i]); if (err) { pr_err("coresight-syscfg: Failed to load configuration %s\n", config_descs[i]->name); @@ -734,6 +805,7 @@ static void cscfg_clear_device(void) list_for_each_entry(cfg_desc, &cscfg_mgr->config_desc_list, item) { etm_perf_del_symlink_cscfg(cfg_desc); } + cscfg_configfs_release(cscfg_mgr); device_unregister(cscfg_device()); mutex_unlock(&cscfg_mutex); } @@ -747,6 +819,10 @@ int __init cscfg_init(void) if (err) return err; + err = cscfg_configfs_init(cscfg_mgr); + if (err) + goto exit_err; + INIT_LIST_HEAD(&cscfg_mgr->csdev_desc_list); INIT_LIST_HEAD(&cscfg_mgr->feat_desc_list); INIT_LIST_HEAD(&cscfg_mgr->config_desc_list); diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h index 7bb8c8e497ba..8d018efd6ead 100644 --- a/drivers/hwtracing/coresight/coresight-syscfg.h +++ b/drivers/hwtracing/coresight/coresight-syscfg.h @@ -6,6 +6,7 @@ #ifndef CORESIGHT_SYSCFG_H #define CORESIGHT_SYSCFG_H +#include #include #include @@ -25,6 +26,7 @@ * @feat_desc_list: List of feature descriptors to load into registered devices. * @config_desc_list: List of system configuration descriptors to load into registered devices. * @sys_active_cnt: Total number of active config descriptor references. + * @cfgfs_subsys: configfs subsystem used to manage configurations. */ struct cscfg_manager { struct device dev; @@ -32,6 +34,7 @@ struct cscfg_manager { struct list_head feat_desc_list; struct list_head config_desc_list; atomic_t sys_active_cnt; + struct configfs_subsystem cfgfs_subsys; }; /* get reference to dev in cscfg_manager */ @@ -57,6 +60,10 @@ struct cscfg_registered_csdev { int __init cscfg_init(void); void cscfg_exit(void); int cscfg_preload(void); +const struct cscfg_feature_desc *cscfg_get_named_feat_desc(const char *name); +int cscfg_update_feat_param_val(struct cscfg_feature_desc *feat_desc, + int param_idx, u64 value); + /* syscfg manager external API */ int cscfg_load_config_sets(struct cscfg_config_desc **cfg_descs, -- cgit v1.2.3 From f71cd93d5ea49c9993a30bea4e64d704d3caca26 Mon Sep 17 00:00:00 2001 From: Mike Leach Date: Wed, 18 Aug 2021 13:40:21 -0600 Subject: Documentation: coresight: Add documentation for CoreSight config Adds documentation for the CoreSight System configuration manager. Link: https://lore.kernel.org/r/20210723165444.1048-11-mike.leach@linaro.org [Fixed coresight-config.rst documentation link] Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Signed-off-by: Mike Leach Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-11-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- Documentation/trace/coresight/coresight-config.rst | 244 +++++++++++++++++++++ Documentation/trace/coresight/coresight.rst | 15 ++ 2 files changed, 259 insertions(+) create mode 100644 Documentation/trace/coresight/coresight-config.rst diff --git a/Documentation/trace/coresight/coresight-config.rst b/Documentation/trace/coresight/coresight-config.rst new file mode 100644 index 000000000000..a4e3ef295240 --- /dev/null +++ b/Documentation/trace/coresight/coresight-config.rst @@ -0,0 +1,244 @@ +.. SPDX-License-Identifier: GPL-2.0 + +====================================== +CoreSight System Configuration Manager +====================================== + + :Author: Mike Leach + :Date: October 2020 + +Introduction +============ + +The CoreSight System Configuration manager is an API that allows the +programming of the CoreSight system with pre-defined configurations that +can then be easily enabled from sysfs or perf. + +Many CoreSight components can be programmed in complex ways - especially ETMs. +In addition, components can interact across the CoreSight system, often via +the cross trigger components such as CTI and CTM. These system settings can +be defined and enabled as named configurations. + + +Basic Concepts +============== + +This section introduces the basic concepts of a CoreSight system configuration. + + +Features +-------- + +A feature is a named set of programming for a CoreSight device. The programming +is device dependent, and can be defined in terms of absolute register values, +resource usage and parameter values. + +The feature is defined using a descriptor. This descriptor is used to load onto +a matching device, either when the feature is loaded into the system, or when the +CoreSight device is registered with the configuration manager. + +The load process involves interpreting the descriptor into a set of register +accesses in the driver - the resource usage and parameter descriptions +translated into appropriate register accesses. This interpretation makes it easy +and efficient for the feature to be programmed onto the device when required. + +The feature will not be active on the device until the feature is enabled, and +the device itself is enabled. When the device is enabled then enabled features +will be programmed into the device hardware. + +A feature is enabled as part of a configuration being enabled on the system. + + +Parameter Value +~~~~~~~~~~~~~~~ + +A parameter value is a named value that may be set by the user prior to the +feature being enabled that can adjust the behaviour of the operation programmed +by the feature. + +For example, this could be a count value in a programmed operation that repeats +at a given rate. When the feature is enabled then the current value of the +parameter is used in programming the device. + +The feature descriptor defines a default value for a parameter, which is used +if the user does not supply a new value. + +Users can update parameter values using the configfs API for the CoreSight +system - which is described below. + +The current value of the parameter is loaded into the device when the feature +is enabled on that device. + + +Configurations +-------------- + +A configuration defines a set of features that are to be used in a trace +session where the configuration is selected. For any trace session only one +configuration may be selected. + +The features defined may be on any type of device that is registered +to support system configuration. A configuration may select features to be +enabled on a class of devices - i.e. any ETMv4, or specific devices, e.g. a +specific CTI on the system. + +As with the feature, a descriptor is used to define the configuration. +This will define the features that must be enabled as part of the configuration +as well as any preset values that can be used to override default parameter +values. + + +Preset Values +~~~~~~~~~~~~~ + +Preset values are easily selectable sets of parameter values for the features +that the configuration uses. The number of values in a single preset set, equals +the sum of parameter values in the features used by the configuration. + +e.g. a configuration consists of 3 features, one has 2 parameters, one has +a single parameter, and another has no parameters. A single preset set will +therefore have 3 values. + +Presets are optionally defined by the configuration, up to 15 can be defined. +If no preset is selected, then the parameter values defined in the feature +are used as normal. + + +Operation +~~~~~~~~~ + +The following steps take place in the operation of a configuration. + +1) In this example, the configuration is 'autofdo', which has an + associated feature 'strobing' that works on ETMv4 CoreSight Devices. + +2) The configuration is enabled. For example 'perf' may select the + configuration as part of its command line:: + + perf record -e cs_etm/autofdo/ myapp + + which will enable the 'autofdo' configuration. + +3) perf starts tracing on the system. As each ETMv4 that perf uses for + trace is enabled, the configuration manager will check if the ETMv4 + has a feature that relates to the currently active configuration. + In this case 'strobing' is enabled & programmed into the ETMv4. + +4) When the ETMv4 is disabled, any registers marked as needing to be + saved will be read back. + +5) At the end of the perf session, the configuration will be disabled. + + +Viewing Configurations and Features +=================================== + +The set of configurations and features that are currently loaded into the +system can be viewed using the configfs API. + +Mount configfs as normal and the 'cs-syscfg' subsystem will appear:: + + $ ls /config + cs-syscfg stp-policy + +This has two sub-directories:: + + $ cd cs-syscfg/ + $ ls + configurations features + +The system has the configuration 'autofdo' built in. It may be examined as +follows:: + + $ cd configurations/ + $ ls + autofdo + $ cd autofdo/ + $ ls + description preset1 preset3 preset5 preset7 preset9 + feature_refs preset2 preset4 preset6 preset8 + $ cat description + Setup ETMs with strobing for autofdo + $ cat feature_refs + strobing + +Each preset declared has a preset subdirectory declared. The values for +the preset can be examined:: + + $ cat preset1/values + strobing.window = 0x1388 strobing.period = 0x2 + $ cat preset2/values + strobing.window = 0x1388 strobing.period = 0x4 + +The features referenced by the configuration can be examined in the features +directory:: + + $ cd ../../features/strobing/ + $ ls + description matches nr_params params + $ cat description + Generate periodic trace capture windows. + parameter 'window': a number of CPU cycles (W) + parameter 'period': trace enabled for W cycles every period x W cycles + $ cat matches + SRC_ETMV4 + $ cat nr_params + 2 + +Move to the params directory to examine and adjust parameters:: + + cd params + $ ls + period window + $ cd period + $ ls + value + $ cat value + 0x2710 + # echo 15000 > value + # cat value + 0x3a98 + +Parameters adjusted in this way are reflected in all device instances that have +loaded the feature. + + +Using Configurations in perf +============================ + +The configurations loaded into the CoreSight configuration management are +also declared in the perf 'cs_etm' event infrastructure so that they can +be selected when running trace under perf:: + + $ ls /sys/devices/cs_etm + configurations format perf_event_mux_interval_ms sinks type + events nr_addr_filters power + +Key directories here are 'configurations' - which lists the loaded +configurations, and 'events' - a generic perf directory which allows +selection on the perf command line.:: + + $ ls configurations/ + autofdo + $ cat configurations/autofdo + 0xa7c3dddd + +As with the sinks entries, this provides a hash of the configuration name. +The entry in the 'events' directory uses perfs built in syntax generator +to substitute the syntax for the name when evaluating the command:: + + $ ls events/ + autofdo + $ cat events/autofdo + configid=0xa7c3dddd + +The 'autofdo' configuration may be selected on the perf command line:: + + $ perf record -e cs_etm/autofdo/u --per-thread + +A preset to override the current parameter values can also be selected:: + + $ perf record -e cs_etm/autofdo,preset=1/u --per-thread + +When configurations are selected in this way, then the trace sink used is +automatically selected. diff --git a/Documentation/trace/coresight/coresight.rst b/Documentation/trace/coresight/coresight.rst index 1ec8dc35b1d8..a15571d96cc8 100644 --- a/Documentation/trace/coresight/coresight.rst +++ b/Documentation/trace/coresight/coresight.rst @@ -620,6 +620,19 @@ channels on the CTM (Cross Trigger Matrix). A separate documentation file is provided to explain the use of these devices. (Documentation/trace/coresight/coresight-ect.rst) [#fourth]_. +CoreSight System Configuration +------------------------------ + +CoreSight components can be complex devices with many programming options. +Furthermore, components can be programmed to interact with each other across the +complete system. + +A CoreSight System Configuration manager is provided to allow these complex programming +configurations to be selected and used easily from perf and sysfs. + +See the separate document for further information. +(Documentation/trace/coresight/coresight-config.rst) [#fifth]_. + .. [#first] Documentation/ABI/testing/sysfs-bus-coresight-devices-stm @@ -628,3 +641,5 @@ A separate documentation file is provided to explain the use of these devices. .. [#third] https://github.com/Linaro/perf-opencsd .. [#fourth] Documentation/trace/coresight/coresight-ect.rst + +.. [#fifth] Documentation/trace/coresight/coresight-config.rst -- cgit v1.2.3 From 5353dd72f99207e8118a766847df8d60bb559940 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 18 Aug 2021 13:40:22 -0600 Subject: coresight: Replace deprecated CPU-hotplug functions. The functions get_online_cpus() and put_online_cpus() have been deprecated during the CPU hotplug rework. They map directly to cpus_read_lock() and cpus_read_unlock(). Replace deprecated CPU-hotplug functions with the official version. The behavior remains unchanged. Link: https://lore.kernel.org/r/20210803141621.780504-15-bigeasy@linutronix.de Cc: Mathieu Poirier Cc: Suzuki K Poulose Cc: Mike Leach Cc: Leo Yan Cc: Alexander Shishkin Cc: coresight@lists.linaro.org Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Mathieu Poirier Link: https://lore.kernel.org/r/20210818194022.379573-12-mathieu.poirier@linaro.org Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight-cpu-debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hwtracing/coresight/coresight-cpu-debug.c b/drivers/hwtracing/coresight/coresight-cpu-debug.c index 9731d3a96073..00de46565bc4 100644 --- a/drivers/hwtracing/coresight/coresight-cpu-debug.c +++ b/drivers/hwtracing/coresight/coresight-cpu-debug.c @@ -588,11 +588,11 @@ static int debug_probe(struct amba_device *adev, const struct amba_id *id) drvdata->base = base; - get_online_cpus(); + cpus_read_lock(); per_cpu(debug_drvdata, drvdata->cpu) = drvdata; ret = smp_call_function_single(drvdata->cpu, debug_init_arch_data, drvdata, 1); - put_online_cpus(); + cpus_read_unlock(); if (ret) { dev_err(dev, "CPU%d debug arch init failed\n", drvdata->cpu); -- cgit v1.2.3 From d1f278da6b11585f05b2755adfc8851cbf14a1ec Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Wed, 18 Aug 2021 19:29:39 -0700 Subject: lkdtm: replace SCSI_DISPATCH_CMD with SCSI_QUEUE_RQ When scsi_dispatch_cmd was moved to scsi_lib.c and made static, some compilers (i.e., at least gcc 8.4.0) decided to compile this inline. This is a problem for lkdtm.ko, which inserted a kprobe on this function for the SCSI_DISPATCH_CMD crashpoint. Move this crashpoint one function up the call chain to scsi_queue_rq. Though this is also a static function, it should never be inlined because it is assigned as a structure entry. Therefore, kprobe_register should always be able to find it. Fixes: 82042a2cdb55 ("scsi: move scsi_dispatch_cmd to scsi_lib.c") Acked-by: Kees Cook Signed-off-by: Kevin Mitchell Link: https://lore.kernel.org/r/20210819022940.561875-2-kevmitch@arista.com Signed-off-by: Greg Kroah-Hartman --- Documentation/fault-injection/provoke-crashes.rst | 2 +- drivers/misc/lkdtm/core.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/fault-injection/provoke-crashes.rst b/Documentation/fault-injection/provoke-crashes.rst index a20ba5d93932..18de17354206 100644 --- a/Documentation/fault-injection/provoke-crashes.rst +++ b/Documentation/fault-injection/provoke-crashes.rst @@ -29,7 +29,7 @@ recur_count cpoint_name Where in the kernel to trigger the action. It can be one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY, - FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD, + FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, IDE_CORE_CP, or DIRECT cpoint_type diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 486ce0cfde03..579c3d84a29c 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -81,7 +81,7 @@ static struct crashpoint crashpoints[] = { CRASHPOINT("FS_DEVRW", "ll_rw_block"), CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), CRASHPOINT("TIMERADD", "hrtimer_start"), - CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"), + CRASHPOINT("SCSI_QUEUE_RQ", "scsi_queue_rq"), CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), #endif }; -- cgit v1.2.3 From b2159182dd498fdb0f49e371ccc94efbc12d1f8e Mon Sep 17 00:00:00 2001 From: Kevin Mitchell Date: Wed, 18 Aug 2021 19:29:40 -0700 Subject: lkdtm: remove IDE_CORE_CP crashpoint With the removal of the legacy IDE driver in kb7fb14d3ac63 ("ide: remove the legacy ide driver"), this crashpoint no longer points to a valid function. Acked-by: Kees Cook Signed-off-by: Kevin Mitchell Link: https://lore.kernel.org/r/20210819022940.561875-3-kevmitch@arista.com Signed-off-by: Greg Kroah-Hartman --- Documentation/fault-injection/provoke-crashes.rst | 3 +-- drivers/misc/lkdtm/core.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Documentation/fault-injection/provoke-crashes.rst b/Documentation/fault-injection/provoke-crashes.rst index 18de17354206..3abe84225613 100644 --- a/Documentation/fault-injection/provoke-crashes.rst +++ b/Documentation/fault-injection/provoke-crashes.rst @@ -29,8 +29,7 @@ recur_count cpoint_name Where in the kernel to trigger the action. It can be one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY, - FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, - IDE_CORE_CP, or DIRECT + FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_QUEUE_RQ, or DIRECT. cpoint_type Indicates the action to be taken on hitting the crash point. diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c index 579c3d84a29c..95b1c6800a22 100644 --- a/drivers/misc/lkdtm/core.c +++ b/drivers/misc/lkdtm/core.c @@ -82,7 +82,6 @@ static struct crashpoint crashpoints[] = { CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"), CRASHPOINT("TIMERADD", "hrtimer_start"), CRASHPOINT("SCSI_QUEUE_RQ", "scsi_queue_rq"), - CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"), #endif }; -- cgit v1.2.3 From 34633219b8947314d369ddf7bc2e45ac5aec7765 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 21 Jul 2021 20:07:38 -0700 Subject: phy: qmp: Provide unique clock names for DP clocks The USB/DP combo PHY exposes the "qmp_dp_phy_pll_link_clk" and "qmp_dp_phy_pll_vco_div_clk" clocks, that are consumed by the display clock controller. But for boards with multiple enabled QMP USB/DP combo instances the hard coded names collides - and hence only the first probed device is allowed to register. Given that clocks are no longer reference globally by name and it's possible to replace the hard coded names by something unique, but still user friendly. The two new clock names are based on dev_name() and results in names such as "88ee000.phy::link_clk" and "88ee000.phy::vco_div_clk". Signed-off-by: Bjorn Andersson Reviewed-by: Stephen Boyd Link: https://lore.kernel.org/r/20210722030738.3385821-1-bjorn.andersson@linaro.org Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index dd6174084600..a8c4368f984b 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -5195,6 +5195,7 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy, { struct clk_init_data init = { }; struct qmp_phy_dp_clks *dp_clks; + char name[64]; int ret; dp_clks = devm_kzalloc(qmp->dev, sizeof(*dp_clks), GFP_KERNEL); @@ -5204,15 +5205,17 @@ static int phy_dp_clks_register(struct qcom_qmp *qmp, struct qmp_phy *qphy, dp_clks->qphy = qphy; qphy->dp_clks = dp_clks; + snprintf(name, sizeof(name), "%s::link_clk", dev_name(qmp->dev)); init.ops = &qcom_qmp_dp_link_clk_ops; - init.name = "qmp_dp_phy_pll_link_clk"; + init.name = name; dp_clks->dp_link_hw.init = &init; ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_link_hw); if (ret) return ret; + snprintf(name, sizeof(name), "%s::vco_div_clk", dev_name(qmp->dev)); init.ops = &qcom_qmp_dp_pixel_clk_ops; - init.name = "qmp_dp_phy_pll_vco_div_clk"; + init.name = name; dp_clks->dp_pixel_hw.init = &init; ret = devm_clk_hw_register(qmp->dev, &dp_clks->dp_pixel_hw); if (ret) -- cgit v1.2.3 From 80f652c2661a4f1ed999c28294ebc43847d1b1e7 Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Sat, 21 Aug 2021 18:56:55 +0300 Subject: dt-bindings: phy: qcom,qmp: Add SM6115 UFS PHY bindings Add the compatible strings for the UFS PHY found on SM4250/6115 SoC. Signed-off-by: Iskren Chernev Acked-by: Rob Herring Link: https://lore.kernel.org/r/20210821155657.893165-2-iskren.chernev@gmail.com Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml index 47d99001d2dd..75be5650a198 100644 --- a/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml +++ b/Documentation/devicetree/bindings/phy/qcom,qmp-phy.yaml @@ -36,6 +36,7 @@ properties: - qcom,sdm845-qmp-ufs-phy - qcom,sdm845-qmp-usb3-phy - qcom,sdm845-qmp-usb3-uni-phy + - qcom,sm6115-qmp-ufs-phy - qcom,sm8150-qmp-ufs-phy - qcom,sm8150-qmp-usb3-phy - qcom,sm8150-qmp-usb3-uni-phy -- cgit v1.2.3 From 152a810eae03f16e982444ffe3b0eca933a750cd Mon Sep 17 00:00:00 2001 From: Iskren Chernev Date: Sat, 21 Aug 2021 18:56:56 +0300 Subject: phy: qcom-qmp: Add support for SM6115 UFS phy Add the tables and constants for init sequences for UFS QMP phy found in SM4250/6115 SoC. The phy is a variation of the v2 phy, but is mistakenly labeled as v3-660 in downstream sources. QSERDES COM, RX, TX registers match fully existing v2 registers, with a few additions. PCS registers don't have much in common, but there are no clashes with existing ones so new registers were added to existing v2 PCS pack. Signed-off-by: Iskren Chernev Link: https://lore.kernel.org/r/20210821155657.893165-3-iskren.chernev@gmail.com Signed-off-by: Vinod Koul --- drivers/phy/qualcomm/phy-qcom-qmp.c | 124 ++++++++++++++++++++++++++++++++++++ drivers/phy/qualcomm/phy-qcom-qmp.h | 18 ++++++ 2 files changed, 142 insertions(+) diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index a8c4368f984b..f14032170b1c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -234,6 +234,11 @@ static const unsigned int sdm845_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_PCS_READY_STATUS] = 0x160, }; +static const unsigned int sm6115_ufsphy_regs_layout[QPHY_LAYOUT_SIZE] = { + [QPHY_START_CTRL] = 0x00, + [QPHY_PCS_READY_STATUS] = 0x168, +}; + static const unsigned int sm8250_pcie_regs_layout[QPHY_LAYOUT_SIZE] = { [QPHY_SW_RESET] = 0x00, [QPHY_START_CTRL] = 0x44, @@ -1329,6 +1334,97 @@ static const struct qmp_phy_init_tbl qmp_v3_usb3_uniphy_pcs_tbl[] = { QMP_PHY_INIT_CFG(QPHY_V3_PCS_REFGEN_REQ_CONFIG2, 0x60), }; +static const struct qmp_phy_init_tbl sm6115_ufsphy_serdes_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x0e), + QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), + QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30), + QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x01), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), + QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x04), + QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE0, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE0, 0x02), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE1, 0x98), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE1, 0x0b), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE1, 0x16), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE1, 0x28), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80), + QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE2_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE1, 0x32), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE1, 0x00), + QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL1, 0xff), + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_INITVAL2, 0x00), + + /* Rate B */ + QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x44), +}; + +static const struct qmp_phy_init_tbl sm6115_ufsphy_tx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), + QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x06), +}; + +static const struct qmp_phy_init_tbl sm6115_ufsphy_rx_tbl[] = { + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_LVL, 0x24), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x0F), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_INTERFACE_MODE, 0x40), + QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x1E), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_TERM_BW, 0x5B), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x3F), + QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0D), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_HALF, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SVS_SO_GAIN, 0x04), + QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x5B), +}; + +static const struct qmp_phy_init_tbl sm6115_ufsphy_pcs_tbl[] = { + QMP_PHY_INIT_CFG(QPHY_RX_PWM_GEAR_BAND, 0x15), + QMP_PHY_INIT_CFG(QPHY_RX_SIGDET_CTRL2, 0x6d), + QMP_PHY_INIT_CFG(QPHY_TX_LARGE_AMP_DRV_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_TX_SMALL_AMP_DRV_LVL, 0x02), + QMP_PHY_INIT_CFG(QPHY_RX_MIN_STALL_NOCONFIG_TIME_CAP, 0x28), + QMP_PHY_INIT_CFG(QPHY_RX_SYM_RESYNC_CTRL, 0x03), + QMP_PHY_INIT_CFG(QPHY_TX_LARGE_AMP_POST_EMP_LVL, 0x12), + QMP_PHY_INIT_CFG(QPHY_TX_SMALL_AMP_POST_EMP_LVL, 0x0f), + QMP_PHY_INIT_CFG(QPHY_RX_MIN_HIBERN8_TIME, 0x9a), /* 8 us */ +}; + static const struct qmp_phy_init_tbl sdm845_ufsphy_serdes_tbl[] = { QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04), @@ -3396,6 +3492,31 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { .no_pcs_sw_reset = true, }; +static const struct qmp_phy_cfg sm6115_ufsphy_cfg = { + .type = PHY_TYPE_UFS, + .nlanes = 1, + + .serdes_tbl = sm6115_ufsphy_serdes_tbl, + .serdes_tbl_num = ARRAY_SIZE(sm6115_ufsphy_serdes_tbl), + .tx_tbl = sm6115_ufsphy_tx_tbl, + .tx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_tx_tbl), + .rx_tbl = sm6115_ufsphy_rx_tbl, + .rx_tbl_num = ARRAY_SIZE(sm6115_ufsphy_rx_tbl), + .pcs_tbl = sm6115_ufsphy_pcs_tbl, + .pcs_tbl_num = ARRAY_SIZE(sm6115_ufsphy_pcs_tbl), + .clk_list = sdm845_ufs_phy_clk_l, + .num_clks = ARRAY_SIZE(sdm845_ufs_phy_clk_l), + .vreg_list = qmp_phy_vreg_l, + .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), + .regs = sm6115_ufsphy_regs_layout, + + .start_ctrl = SERDES_START, + .pwrdn_ctrl = SW_PWRDN, + + .is_dual_lane_phy = false, + .no_pcs_sw_reset = true, +}; + static const struct qmp_phy_cfg msm8998_pciephy_cfg = { .type = PHY_TYPE_PCIE, .nlanes = 1, @@ -5444,6 +5565,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { }, { .compatible = "qcom,msm8998-qmp-usb3-phy", .data = &msm8998_usb3phy_cfg, + }, { + .compatible = "qcom,sm6115-qmp-ufs-phy", + .data = &sm6115_ufsphy_cfg, }, { .compatible = "qcom,sm8150-qmp-ufs-phy", .data = &sm8150_ufsphy_cfg, diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index 6592b58b13f6..bebeac2c091c 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h @@ -191,6 +191,8 @@ #define QSERDES_COM_VCO_TUNE2_MODE0 0x130 #define QSERDES_COM_VCO_TUNE1_MODE1 0x134 #define QSERDES_COM_VCO_TUNE2_MODE1 0x138 +#define QSERDES_COM_VCO_TUNE_INITVAL1 0x13c +#define QSERDES_COM_VCO_TUNE_INITVAL2 0x140 #define QSERDES_COM_VCO_TUNE_TIMER1 0x144 #define QSERDES_COM_VCO_TUNE_TIMER2 0x148 #define QSERDES_COM_BG_CTRL 0x170 @@ -220,6 +222,10 @@ /* Only for QMP V2 PHY - RX registers */ #define QSERDES_RX_UCDR_SO_GAIN_HALF 0x010 #define QSERDES_RX_UCDR_SO_GAIN 0x01c +#define QSERDES_RX_UCDR_SVS_SO_GAIN_HALF 0x030 +#define QSERDES_RX_UCDR_SVS_SO_GAIN_QUARTER 0x034 +#define QSERDES_RX_UCDR_SVS_SO_GAIN_EIGHTH 0x038 +#define QSERDES_RX_UCDR_SVS_SO_GAIN 0x03c #define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN 0x040 #define QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE 0x048 #define QSERDES_RX_RX_TERM_BW 0x090 @@ -243,6 +249,10 @@ #define QPHY_POWER_DOWN_CONTROL 0x04 #define QPHY_TXDEEMPH_M6DB_V0 0x24 #define QPHY_TXDEEMPH_M3P5DB_V0 0x28 +#define QPHY_TX_LARGE_AMP_DRV_LVL 0x34 +#define QPHY_TX_LARGE_AMP_POST_EMP_LVL 0x38 +#define QPHY_TX_SMALL_AMP_DRV_LVL 0x3c +#define QPHY_TX_SMALL_AMP_POST_EMP_LVL 0x40 #define QPHY_ENDPOINT_REFCLK_DRIVE 0x54 #define QPHY_RX_IDLE_DTCT_CNTRL 0x58 #define QPHY_POWER_STATE_CONFIG1 0x60 @@ -253,6 +263,11 @@ #define QPHY_LOCK_DETECT_CONFIG3 0x88 #define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK 0xa0 #define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK 0xa4 +#define QPHY_RX_MIN_STALL_NOCONFIG_TIME_CAP 0xcc +#define QPHY_RX_SYM_RESYNC_CTRL 0x13c +#define QPHY_RX_MIN_HIBERN8_TIME 0x140 +#define QPHY_RX_SIGDET_CTRL2 0x148 +#define QPHY_RX_PWM_GEAR_BAND 0x154 #define QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB 0x1A8 #define QPHY_OSC_DTCT_ACTIONS 0x1AC #define QPHY_RX_SIGDET_LVL 0x1D8 @@ -280,6 +295,8 @@ #define QSERDES_V3_COM_SSC_PER2 0x020 #define QSERDES_V3_COM_SSC_STEP_SIZE1 0x024 #define QSERDES_V3_COM_SSC_STEP_SIZE2 0x028 +#define QSERDES_V3_COM_POST_DIV 0x02c +#define QSERDES_V3_COM_POST_DIV_MUX 0x030 #define QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN 0x034 # define QSERDES_V3_COM_BIAS_EN 0x0001 # define QSERDES_V3_COM_BIAS_EN_MUX 0x0002 @@ -291,6 +308,7 @@ #define QSERDES_V3_COM_CLK_ENABLE1 0x038 #define QSERDES_V3_COM_SYS_CLK_CTRL 0x03c #define QSERDES_V3_COM_SYSCLK_BUF_ENABLE 0x040 +#define QSERDES_V3_COM_PLL_EN 0x044 #define QSERDES_V3_COM_PLL_IVCO 0x048 #define QSERDES_V3_COM_LOCK_CMP1_MODE0 0x098 #define QSERDES_V3_COM_LOCK_CMP2_MODE0 0x09c -- cgit v1.2.3 From ea6942dad4b2a7e1735aa0f10f3d0b04b847750f Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Aug 2021 10:49:52 +0800 Subject: soundwire: intel: fix potential race condition during power down The power down sequence sets the link_up flag as false outside of the mutex_lock. This is potentially unsafe. In additional the flow in that sequence can be improved by first testing if the link was powered, setting the link_up flag as false and proceeding with the power down. In case the CPA bits cannot be cleared, we only flag an error since we cannot deal with interrupts any longer. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Ranjani Sridharan Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210818024954.16873-2-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 9794bc222fb5..808dda1380c2 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -538,12 +538,14 @@ static int intel_link_power_down(struct sdw_intel *sdw) mutex_lock(sdw->link_res->shim_lock); - intel_shim_master_ip_to_glue(sdw); - if (!(*shim_mask & BIT(link_id))) dev_err(sdw->cdns.dev, "%s: Unbalanced power-up/down calls\n", __func__); + sdw->cdns.link_up = false; + + intel_shim_master_ip_to_glue(sdw); + *shim_mask &= ~BIT(link_id); if (!*shim_mask) { @@ -560,18 +562,19 @@ static int intel_link_power_down(struct sdw_intel *sdw) link_control &= spa_mask; ret = intel_clear_bit(shim, SDW_SHIM_LCTL, link_control, cpa_mask); + if (ret < 0) { + dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__); + + /* + * we leave the sdw->cdns.link_up flag as false since we've disabled + * the link at this point and cannot handle interrupts any longer. + */ + } } mutex_unlock(sdw->link_res->shim_lock); - if (ret < 0) { - dev_err(sdw->cdns.dev, "%s: could not power down link\n", __func__); - - return ret; - } - - sdw->cdns.link_up = false; - return 0; + return ret; } static void intel_shim_sync_arm(struct sdw_intel *sdw) -- cgit v1.2.3 From e4401abb3485d78eb7987866a4b834f94bb60d90 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Aug 2021 10:49:53 +0800 Subject: soundwire: intel: skip suspend/resume/wake when link was not started The SoundWire Linux devices are created purely based on information provided by platform firmware (e.g. ACPI DSDT table). When the kernel finds a matching driver for the device address (_ADR), the probe will initialize required data structures and initialize pm ops. When the SoundWire link is started at a later point, the physical devices will synchronize on the SoundWire frames and report their attachment status, thereby triggering the enumeration and initialization of device registers. This two-step solution was a conscious design decision to allow e.g. a driver to use sideband mechanisms to turn power rails on. This can also allow OEMs to describe multiple platforms with the same DSDT table, the devices that are not physically present in hardware. The drawback of this approach is a bit of confusion, with more devices than are actually present in hardware. This results in 'ghost' devices, for which the driver successfully probes, but that will not generate any traffic on the bus. suspend-resume transitions are handled by drivers, and skipped when the devices are not physically present. This patch provides a work-around for a second-level of confusion in platform firmware: some platforms only use HDaudio links, but nevertheless expose SoundWire 'ghost' devices. This results in error messages in the Intel driver while trying to suspend/resume these links. The simplest solution is to add a boolean status flag to skip all suspend/resume/wake sequences if the link was never started. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210818024954.16873-3-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 22 ++++++++++++---------- drivers/soundwire/intel.h | 1 + 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 808dda1380c2..8b42053b171f 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1525,6 +1525,7 @@ int intel_link_startup(struct auxiliary_device *auxdev) if (!(link_flags & SDW_INTEL_MASTER_DISABLE_PM_RUNTIME_IDLE)) pm_runtime_idle(dev); + sdw->startup_done = true; return 0; err_interrupt: @@ -1564,8 +1565,9 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) sdw = dev_get_drvdata(dev); bus = &sdw->cdns.bus; - if (bus->prop.hw_disabled) { - dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", bus->link_id); + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", + bus->link_id); return 0; } @@ -1602,8 +1604,8 @@ static int __maybe_unused intel_suspend(struct device *dev) u32 clock_stop_quirks; int ret; - if (bus->prop.hw_disabled) { - dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", bus->link_id); return 0; } @@ -1656,8 +1658,8 @@ static int __maybe_unused intel_suspend_runtime(struct device *dev) u32 clock_stop_quirks; int ret; - if (bus->prop.hw_disabled) { - dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", bus->link_id); return 0; } @@ -1721,8 +1723,8 @@ static int __maybe_unused intel_resume(struct device *dev) bool multi_link; int ret; - if (bus->prop.hw_disabled) { - dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", bus->link_id); return 0; } @@ -1819,8 +1821,8 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) int status; int ret; - if (bus->prop.hw_disabled) { - dev_dbg(dev, "SoundWire master %d is disabled, ignoring\n", + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", bus->link_id); return 0; } diff --git a/drivers/soundwire/intel.h b/drivers/soundwire/intel.h index 0b47b148da3f..cd93a44dba9a 100644 --- a/drivers/soundwire/intel.h +++ b/drivers/soundwire/intel.h @@ -41,6 +41,7 @@ struct sdw_intel { struct sdw_cdns cdns; int instance; struct sdw_intel_link_res *link_res; + bool startup_done; #ifdef CONFIG_DEBUG_FS struct dentry *debugfs; #endif -- cgit v1.2.3 From 029bfd1cd53cd8ba896a676e5c1bcf6cd0100d3c Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Aug 2021 10:49:54 +0800 Subject: soundwire: intel: conditionally exit clock stop mode on system suspend Intel stress tests reported issues with the clock stop mode, specifically when trying to do a system suspend while the link is already pm_runtime suspended. In this case, we need to disable the shim wake, but when the PCI parent device is also pm_runtime suspended the SHIM registers are not accessible. Since this is an invalid corner case, this patch suggests a pm_runtime resume of the entire bus to full power (parent+child devices) before the system suspend so that the shim wake can be disabled. Unlike the suspend operation, the .prepare callbacks are propagated from root device to leaf devices. By adding a .prepare callback at the SoundWire link level, we can double-check the pm_runtime status of the device as well as its parent PCI device. When the problematic configuration is detected, the device is pm_runtime resumed - which by construction also resume its parent. An additional loop is added to resume all child devices. In theory we only need to restart the link, but doing so will also cause the physical devices to synchronize and re-initialize, while their Linux devices remain pm_runtime suspended. It's simpler to make sure the codec devices are fully resumed so that we don't have to deal with zombie states. This additional loop could have been avoided by adding a .prepare callback in SoundWire codec drivers. Functionally this would have been equivalent. The rationale for implementing a loop at the link level is only to reduce the amount of code required to deal at the codec level with an Intel corner case - in other words keep codec drivers independent from Intel platform-specific programming sequences. BugLink: https://github.com/thesofproject/linux/issues/2606 Signed-off-by: Pierre-Louis Bossart Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210818024954.16873-4-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/intel.c | 107 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c index 8b42053b171f..f66fcbc33a2f 100644 --- a/drivers/soundwire/intel.c +++ b/drivers/soundwire/intel.c @@ -1596,6 +1596,87 @@ int intel_link_process_wakeen_event(struct auxiliary_device *auxdev) * PM calls */ +static int intel_resume_child_device(struct device *dev, void *data) +{ + int ret; + struct sdw_slave *slave = dev_to_sdw_dev(dev); + + if (!slave->probed) { + dev_dbg(dev, "%s: skipping device, no probed driver\n", __func__); + return 0; + } + if (!slave->dev_num_sticky) { + dev_dbg(dev, "%s: skipping device, never detected on bus\n", __func__); + return 0; + } + + ret = pm_request_resume(dev); + if (ret < 0) + dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); + + return ret; +} + +static int __maybe_unused intel_pm_prepare(struct device *dev) +{ + struct sdw_cdns *cdns = dev_get_drvdata(dev); + struct sdw_intel *sdw = cdns_to_intel(cdns); + struct sdw_bus *bus = &cdns->bus; + u32 clock_stop_quirks; + int ret = 0; + + if (bus->prop.hw_disabled || !sdw->startup_done) { + dev_dbg(dev, "SoundWire master %d is disabled or not-started, ignoring\n", + bus->link_id); + return 0; + } + + clock_stop_quirks = sdw->link_res->clock_stop_quirks; + + if (pm_runtime_suspended(dev) && + pm_runtime_suspended(dev->parent) && + ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) || + !clock_stop_quirks)) { + /* + * if we've enabled clock stop, and the parent is suspended, the SHIM registers + * are not accessible and the shim wake cannot be disabled. + * The only solution is to resume the entire bus to full power + */ + + /* + * If any operation in this block fails, we keep going since we don't want + * to prevent system suspend from happening and errors should be recoverable + * on resume. + */ + + /* + * first resume the device for this link. This will also by construction + * resume the PCI parent device. + */ + ret = pm_request_resume(dev); + if (ret < 0) { + dev_err(dev, "%s: pm_request_resume failed: %d\n", __func__, ret); + return 0; + } + + /* + * Continue resuming the entire bus (parent + child devices) to exit + * the clock stop mode. If there are no devices connected on this link + * this is a no-op. + * The resume to full power could have been implemented with a .prepare + * step in SoundWire codec drivers. This would however require a lot + * of code to handle an Intel-specific corner case. It is simpler in + * practice to add a loop at the link level. + */ + ret = device_for_each_child(bus->dev, NULL, intel_resume_child_device); + + if (ret < 0) + dev_err(dev, "%s: intel_resume_child_device failed: %d\n", __func__, ret); + } + + return 0; +} + static int __maybe_unused intel_suspend(struct device *dev) { struct sdw_cdns *cdns = dev_get_drvdata(dev); @@ -1615,19 +1696,18 @@ static int __maybe_unused intel_suspend(struct device *dev) clock_stop_quirks = sdw->link_res->clock_stop_quirks; - if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET || - !clock_stop_quirks) && - !pm_runtime_suspended(dev->parent)) { - - /* - * if we've enabled clock stop, and the parent - * is still active, disable shim wake. The - * SHIM registers are not accessible if the - * parent is already pm_runtime suspended so - * it's too late to change that configuration - */ - - intel_shim_wake(sdw, false); + if ((clock_stop_quirks & SDW_INTEL_CLK_STOP_BUS_RESET) || + !clock_stop_quirks) { + + if (pm_runtime_suspended(dev->parent)) { + /* + * paranoia check: this should not happen with the .prepare + * resume to full power + */ + dev_err(dev, "%s: invalid config: parent is suspended\n", __func__); + } else { + intel_shim_wake(sdw, false); + } } return 0; @@ -1992,6 +2072,7 @@ static int __maybe_unused intel_resume_runtime(struct device *dev) } static const struct dev_pm_ops intel_pm = { + .prepare = intel_pm_prepare, SET_SYSTEM_SLEEP_PM_OPS(intel_suspend, intel_resume) SET_RUNTIME_PM_OPS(intel_suspend_runtime, intel_resume_runtime, NULL) }; -- cgit v1.2.3 From 2564a2d4418bac166a9db2d6ca2f8b99953b1df5 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Wed, 18 Aug 2021 11:01:30 +0800 Subject: soundwire: cadence: do not extend reset delay The duration of the hw_reset is defined as 4096 cycles. The Cadence IP allows for an additional delay which doesn't seem necessary in practice: the actual reset sequence duration is defined by the sync_go mechanism, not by the IP itself. Signed-off-by: Pierre-Louis Bossart Reviewed-by: Rander Wang Signed-off-by: Bard Liao Link: https://lore.kernel.org/r/20210818030130.17113-1-yung-chuan.liao@linux.intel.com Signed-off-by: Vinod Koul --- drivers/soundwire/cadence_master.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/soundwire/cadence_master.c b/drivers/soundwire/cadence_master.c index 0b7f037e6cd0..4fcc3ba93004 100644 --- a/drivers/soundwire/cadence_master.c +++ b/drivers/soundwire/cadence_master.c @@ -1032,10 +1032,7 @@ EXPORT_SYMBOL(sdw_cdns_check_self_clearing_bits); */ int sdw_cdns_exit_reset(struct sdw_cdns *cdns) { - /* program maximum length reset to be safe */ - cdns_updatel(cdns, CDNS_MCP_CONTROL, - CDNS_MCP_CONTROL_RST_DELAY, - CDNS_MCP_CONTROL_RST_DELAY); + /* keep reset delay unchanged to 4096 cycles */ /* use hardware generated reset */ cdns_updatel(cdns, CDNS_MCP_CONTROL, -- cgit v1.2.3 From 0be883a0d795d9146f5325de582584147dd0dcdc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Jul 2021 11:07:10 +0100 Subject: parport: remove non-zero check on count The check for count appears to be incorrect since a non-zero count check occurs a couple of statements earlier. Currently the check is always false and the dev->port->irq != PARPORT_IRQ_NONE part of the check is never tested and the if statement is dead-code. Fix this by removing the check on count. Note that this code is pre-git history, so I can't find a sha for it. Acked-by: Sudip Mukherjee Signed-off-by: Colin Ian King Addresses-Coverity: ("Logically dead code") Link: https://lore.kernel.org/r/20210730100710.27405-1-colin.king@canonical.com Signed-off-by: Greg Kroah-Hartman --- drivers/parport/ieee1284_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 2c11bd3fe1fd..17061f1df0f4 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -518,7 +518,7 @@ size_t parport_ieee1284_ecp_read_data (struct parport *port, goto out; /* Yield the port for a while. */ - if (count && dev->port->irq != PARPORT_IRQ_NONE) { + if (dev->port->irq != PARPORT_IRQ_NONE) { parport_release (dev); schedule_timeout_interruptible(msecs_to_jiffies(40)); parport_claim_or_block (dev); -- cgit v1.2.3 From f8cefead37ddc111786b14da73286204eb8509b5 Mon Sep 17 00:00:00 2001 From: jing yangyang Date: Thu, 19 Aug 2021 19:17:52 -0700 Subject: char: mware: fix returnvar.cocci warnings Remove unneeded variables when "0" can be returned. Generated by: scripts/coccinelle/misc/returnvar.cocci Reported-by: Zeal Robot Signed-off-by: jing yangyang Link: https://lore.kernel.org/r/20210820021752.10927-1-jing.yangyang@zte.com.cn Signed-off-by: Greg Kroah-Hartman --- drivers/char/mwave/tp3780i.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index 8588b51202e5..83eaffeb22c8 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -470,8 +470,6 @@ int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData) int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities) { - int retval = 0; - PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData); @@ -502,7 +500,7 @@ int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n"); - return retval; + return 0; } int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode, -- cgit v1.2.3 From a30dc6cf0dc51419021550152e435736aaef8799 Mon Sep 17 00:00:00 2001 From: Wang Hai Date: Wed, 18 Aug 2021 20:48:45 +0800 Subject: VMCI: fix NULL pointer dereference when unmapping queue pair I got a NULL pointer dereference report when doing fuzz test: Call Trace: qp_release_pages+0xae/0x130 qp_host_unregister_user_memory.isra.25+0x2d/0x80 vmci_qp_broker_unmap+0x191/0x320 ? vmci_host_do_alloc_queuepair.isra.9+0x1c0/0x1c0 vmci_host_unlocked_ioctl+0x59f/0xd50 ? do_vfs_ioctl+0x14b/0xa10 ? tomoyo_file_ioctl+0x28/0x30 ? vmci_host_do_alloc_queuepair.isra.9+0x1c0/0x1c0 __x64_sys_ioctl+0xea/0x120 do_syscall_64+0x34/0xb0 entry_SYSCALL_64_after_hwframe+0x44/0xae When a queue pair is created by the following call, it will not register the user memory if the page_store is NULL, and the entry->state will be set to VMCIQPB_CREATED_NO_MEM. vmci_host_unlocked_ioctl vmci_host_do_alloc_queuepair vmci_qp_broker_alloc qp_broker_alloc qp_broker_create // set entry->state = VMCIQPB_CREATED_NO_MEM; When unmapping this queue pair, qp_host_unregister_user_memory() will be called to unregister the non-existent user memory, which will result in a null pointer reference. It will also change VMCIQPB_CREATED_NO_MEM to VMCIQPB_CREATED_MEM, which should not be present in this operation. Only when the qp broker has mem, it can unregister the user memory when unmapping the qp broker. Only when the qp broker has no mem, it can register the user memory when mapping the qp broker. Fixes: 06164d2b72aa ("VMCI: queue pairs implementation.") Cc: stable Reported-by: Hulk Robot Reviewed-by: Jorgen Hansen Signed-off-by: Wang Hai Link: https://lore.kernel.org/r/20210818124845.488312-1-wanghai38@huawei.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/vmw_vmci/vmci_queue_pair.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index 880c33ab9f47..94ebf7f3fd58 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c @@ -2243,7 +2243,8 @@ int vmci_qp_broker_map(struct vmci_handle handle, result = VMCI_SUCCESS; - if (context_id != VMCI_HOST_CONTEXT_ID) { + if (context_id != VMCI_HOST_CONTEXT_ID && + !QPBROKERSTATE_HAS_MEM(entry)) { struct vmci_qp_page_store page_store; page_store.pages = guest_mem; @@ -2350,7 +2351,8 @@ int vmci_qp_broker_unmap(struct vmci_handle handle, goto out; } - if (context_id != VMCI_HOST_CONTEXT_ID) { + if (context_id != VMCI_HOST_CONTEXT_ID && + QPBROKERSTATE_HAS_MEM(entry)) { qp_acquire_queue_mutex(entry->produce_q); result = qp_save_headers(entry); if (result < VMCI_SUCCESS) -- cgit v1.2.3 From a99009bc4f2f0b46e6c553704fda0b67e04395f5 Mon Sep 17 00:00:00 2001 From: Mihai Carabas Date: Thu, 19 Aug 2021 18:12:26 +0300 Subject: misc/pvpanic: fix set driver data Add again dev_set_drvdata(), but this time in devm_pvpanic_probe(), in order for dev_get_drvdata() to not return NULL. Fixes: 394febc9d0a6 ("misc/pvpanic: Make 'pvpanic_probe()' resource managed") Reviewed-by: Andy Shevchenko Signed-off-by: Mihai Carabas Link: https://lore.kernel.org/r/1629385946-4584-2-git-send-email-mihai.carabas@oracle.com Signed-off-by: Greg Kroah-Hartman --- drivers/misc/pvpanic/pvpanic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c index 02b807c788c9..bb7aa6368538 100644 --- a/drivers/misc/pvpanic/pvpanic.c +++ b/drivers/misc/pvpanic/pvpanic.c @@ -85,6 +85,8 @@ int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi) list_add(&pi->list, &pvpanic_list); spin_unlock(&pvpanic_lock); + dev_set_drvdata(dev, pi); + return devm_add_action_or_reset(dev, pvpanic_remove, pi); } EXPORT_SYMBOL_GPL(devm_pvpanic_probe); -- cgit v1.2.3 From 0dc3ad3f859d3a65b335c861ec342d31d91e8bc8 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 27 Aug 2021 21:21:25 +0200 Subject: Revert "bus: mhi: Add inbound buffers allocation flag" This reverts commit 0092a1e3f7636ff4e202a41b0320690699247e22 This should be reverted in the char-misc-next branch to make merging with Linus's branch possible due to issues with the mhi code that was found in the networking tree. Link: https://lore.kernel.org/r/20210827175852.GB15018@thinkpad Reported-by: Manivannan Sadhasivam Reported-by: Stephen Rothwell Cc: Arnd Bergmann Cc: Bhaumik Bhatt Cc: Hemant Kumar Cc: Jakub Kicinski Cc: Kalle Valo Cc: Loic Poulain Cc: Manivannan Sadhasivam Signed-off-by: Greg Kroah-Hartman --- drivers/bus/mhi/core/internal.h | 2 +- drivers/bus/mhi/core/main.c | 9 +++------ drivers/net/mhi/net.c | 2 +- drivers/net/wwan/mhi_wwan_ctrl.c | 2 +- include/linux/mhi.h | 7 +------ net/qrtr/mhi.c | 2 +- 6 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index 721739c5e0d5..3a732afaf73e 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -682,7 +682,7 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info); void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl); int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan, unsigned int flags); + struct mhi_chan *mhi_chan); int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index c01ec2fef02c..b15c5bc37dd4 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1430,7 +1430,7 @@ exit_unprepare_channel: } int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan, unsigned int flags) + struct mhi_chan *mhi_chan) { int ret = 0; struct device *dev = &mhi_chan->mhi_dev->dev; @@ -1455,9 +1455,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, if (ret) goto error_pm_state; - if (mhi_chan->dir == DMA_FROM_DEVICE) - mhi_chan->pre_alloc = !!(flags & MHI_CH_INBOUND_ALLOC_BUFS); - /* Pre-allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { int nr_el = get_nr_avail_ring_elements(mhi_cntrl, @@ -1613,7 +1610,7 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) } /* Move channel to start state */ -int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, unsigned int flags) +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) { int ret, dir; struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; @@ -1624,7 +1621,7 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, unsigned int flags) if (!mhi_chan) continue; - ret = mhi_prepare_channel(mhi_cntrl, mhi_chan, flags); + ret = mhi_prepare_channel(mhi_cntrl, mhi_chan); if (ret) goto error_open_chan; } diff --git a/drivers/net/mhi/net.c b/drivers/net/mhi/net.c index 11be6bcdd551..e60e38c1f09d 100644 --- a/drivers/net/mhi/net.c +++ b/drivers/net/mhi/net.c @@ -335,7 +335,7 @@ static int mhi_net_newlink(void *ctxt, struct net_device *ndev, u32 if_id, u64_stats_init(&mhi_netdev->stats.tx_syncp); /* Start MHI channels */ - err = mhi_prepare_for_transfer(mhi_dev, 0); + err = mhi_prepare_for_transfer(mhi_dev); if (err) goto out_err; diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c index d0a98f34c54d..e4d0f696687f 100644 --- a/drivers/net/wwan/mhi_wwan_ctrl.c +++ b/drivers/net/wwan/mhi_wwan_ctrl.c @@ -110,7 +110,7 @@ static int mhi_wwan_ctrl_start(struct wwan_port *port) int ret; /* Start mhi device's channel(s) */ - ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev, 0); + ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev); if (ret) return ret; diff --git a/include/linux/mhi.h b/include/linux/mhi.h index b8ca6943f0b7..9c347f558b8c 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -721,13 +721,8 @@ void mhi_device_put(struct mhi_device *mhi_dev); * host and device execution environments match and * channels are in a DISABLED state. * @mhi_dev: Device associated with the channels - * @flags: MHI channel flags */ -int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, - unsigned int flags); - -/* Automatically allocate and queue inbound buffers */ -#define MHI_CH_INBOUND_ALLOC_BUFS BIT(0) +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev); /** * mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer. diff --git a/net/qrtr/mhi.c b/net/qrtr/mhi.c index c609cb724c25..c269c539d1c4 100644 --- a/net/qrtr/mhi.c +++ b/net/qrtr/mhi.c @@ -84,7 +84,7 @@ static int qcom_mhi_qrtr_probe(struct mhi_device *mhi_dev, int rc; /* start channels */ - rc = mhi_prepare_for_transfer(mhi_dev, MHI_CH_INBOUND_ALLOC_BUFS); + rc = mhi_prepare_for_transfer(mhi_dev); if (rc) return rc; -- cgit v1.2.3