drivers/soundwire/max98363: Support MAX98363 SoundWire device

The MAX98363 smart speaker amp can be connected over SoundWire and be
configured for mainboards to use:

- Data Port 0 and Bulk Register Access is not supported
- Data Port 1 is the 32bit data input for the speaker path

The data port and audio mode properties are filled out as best as
possible with the datasheet as a reference.

The ACPI address for the codec is calculated with the information in
the codec driver combined with the devicetree.cb hierarchy where the
link and unique IDs are extracted from the device path.

For example this device is connected to master link ID 2 and has strap
settings configuring it for unique ID 0.

chip drivers/soundwire/max98363
  register "desc" = ""Left Speaker Amp""
  device generic 2.0 on end
end

This driver was tested with the rex0 reference design by booting
and disassembling the runtime SSDT to ensure that the devices have the
expected address and properties.

Device (SW20)
{
  Name (_ADR, 0x000230019F836300)  // _ADR: Address
  Name (_DDN, "Left Speaker Amp")  // _DDN: DOS Device Name
  Method (_STA, 0, NotSerialized)  // _STA: Status
  {
    Return (0x0F)
  }

  Name (_DSD, Package ()
  {
    ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    Package ()
    {
      Package () { "mipi-sdw-sw-interface-revision", 0x00010000 },
      [...]
      Package () { "mipi-sdw-source-port-list", Zero },
      Package () { "mipi-sdw-sink-port-list", 0x02 }
    },

    ToUUID ("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
    Package ()
    {
      Package () { "mipi-sdw-port-audio-mode-0", "MOD0" },
      Package () { "mipi-sdw-dp-1-sink-subproperties", "SNK1" }
    }
  })
  Name (MOD0, Package ()
  {
    ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    Package ()
    {
      Package () { "mipi-sdw-audio-mode-bus-frequency-configs",
        Package () { 0x00927C00, ... }
      },
      Package () { "mipi-sdw-audio-mode-sampling-frequency-configs",
        Package () { 0x3E80, ... }
      },
      [...]
    }
  })
  Name (SNK1, Package ()
  {
    ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    Package ()
    {
      Package () { "mipi-sdw-data-port-type", Zero },
      [...]
    },

    ToUUID ("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
    Package ()
    {
      Package () { "mipi-sdw-port-audio-mode-0", "MOD0" }
    }
  })
}

BUG=b:269497731
TEST=Verified SSDT for SNDW in the OS

Signed-off-by: Kapil Porwal <kapilporwal@google.com>
Change-Id: Ie56109d615759e3e5e32782c8782cb2f47014ec4
Reviewed-on: https://review.coreboot.org/c/coreboot/+/73278
Reviewed-by: Sridhar Siricilla <sridhar.siricilla@intel.com>
Reviewed-by: Subrata Banik <subratabanik@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/drivers/soundwire/max98363/Kconfig b/src/drivers/soundwire/max98363/Kconfig
new file mode 100644
index 0000000..3474d08
--- /dev/null
+++ b/src/drivers/soundwire/max98363/Kconfig
@@ -0,0 +1,6 @@
+config DRIVERS_SOUNDWIRE_MAX98363
+	bool
+	depends on HAVE_ACPI_TABLES
+	default n
+	help
+	  SoundWire MAX98363 audio amp SSDT generator.
diff --git a/src/drivers/soundwire/max98363/Makefile.inc b/src/drivers/soundwire/max98363/Makefile.inc
new file mode 100644
index 0000000..5501eb3
--- /dev/null
+++ b/src/drivers/soundwire/max98363/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_DRIVERS_SOUNDWIRE_MAX98363) += max98363.c
diff --git a/src/drivers/soundwire/max98363/chip.h b/src/drivers/soundwire/max98363/chip.h
new file mode 100644
index 0000000..625fc8c
--- /dev/null
+++ b/src/drivers/soundwire/max98363/chip.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __DRIVERS_SOUNDWIRE_MAX98363_CHIP_H__
+#define __DRIVERS_SOUNDWIRE_MAX98363_CHIP_H__
+
+#include <acpi/acpi.h>
+
+struct drivers_soundwire_max98363_config {
+	char acpi_name[ACPI_NAME_BUFFER_SIZE]; /* Set by the acpi_name ops */
+	const char *desc;
+};
+
+#endif /* __DRIVERS_SOUNDWIRE_MAX98363_CHIP_H__ */
diff --git a/src/drivers/soundwire/max98363/max98363.c b/src/drivers/soundwire/max98363/max98363.c
new file mode 100644
index 0000000..2963cda
--- /dev/null
+++ b/src/drivers/soundwire/max98363/max98363.c
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <acpi/acpigen.h>
+#include <acpi/acpi_device.h>
+#include <acpi/acpi_soundwire.h>
+#include <device/device.h>
+#include <device/path.h>
+#include <device/soundwire.h>
+#include <mipi/ids.h>
+#include <stdio.h>
+
+#include "chip.h"
+
+static struct soundwire_address max98363_address = {
+	.version = SOUNDWIRE_VERSION_1_2,
+	.manufacturer_id = MIPI_MFG_ID_MAXIM,
+	.part_id = MIPI_DEV_ID_MAXIM_MAX98363,
+	.class = MIPI_CLASS_NONE
+};
+
+static struct soundwire_slave max98363_slave = {
+	.wake_up_unavailable = false,
+	.test_mode_supported = false,
+	.clock_stop_mode1_supported = true,
+	.simplified_clockstopprepare_sm_supported = true,
+	.clockstopprepare_hard_reset_behavior = false,
+	.highPHY_capable = false,
+	.paging_supported = false,
+	.bank_delay_supported = false,
+	.port15_read_behavior = false,
+	.source_port_list = 0,
+	.sink_port_list = SOUNDWIRE_PORT(1),
+};
+
+static struct soundwire_audio_mode max98363_audio_mode = {
+	/* Bus frequency must be 2/4/8/16 divider of supported input frequencies. */
+	.bus_frequency_configs_count = 19,
+	.bus_frequency_configs = {
+		9600 * KHz,  4800 * KHz, 2400 * KHz, 1200 * KHz,	/* 19.2 MHz */
+		11289600,    5644800,    2822400,    1411200,		/* 22.5792 MHz */
+		12000 * KHz, 6000 * KHz, 3000 * KHz, 1500 * KHz,	/* 24 MHz */
+		12288 * KHz, 6144 * KHz, 3072 * KHz, 1536 * KHz,	/* 24.576 MHz */
+			     8000 * KHz, 4000 * KHz, 2000 * KHz,	/* 32 MHz (no /2) */
+	},
+	/* Support 16 KHz to 96 KHz sampling frequency */
+	.sampling_frequency_configs_count = 8,
+	.sampling_frequency_configs = {
+		16 * KHz,
+		22.05 * KHz,
+		24 * KHz,
+		32 * KHz,
+		44.1 * KHz,
+		48 * KHz,
+		88.2 * KHz,
+		96 * KHz,
+	},
+	.prepare_channel_behavior = CHANNEL_PREPARE_ANY_FREQUENCY
+};
+
+static struct soundwire_dpn max98363_dp1 = {
+	.port_wordlength_configs_count = 1,
+	.port_wordlength_configs = { 32 },
+	.data_port_type = FULL_DATA_PORT,
+	.max_grouping_supported = BLOCK_GROUP_COUNT_1,
+	.simplified_channelprepare_sm = false,
+	.imp_def_dpn_interrupts_supported = 0,
+	.min_channel_number = 1,
+	.max_channel_number = 1,
+	.modes_supported = MODE_ISOCHRONOUS | MODE_TX_CONTROLLED |
+			   MODE_RX_CONTROLLED | MODE_FULL_ASYNCHRONOUS,
+	.block_packing_mode = true,
+	.port_audio_mode_count = 1,
+	.port_audio_mode_list = { 0 }
+};
+
+static const struct soundwire_codec max98363_codec = {
+	.slave = &max98363_slave,
+	.audio_mode = { &max98363_audio_mode },
+	.dpn = {
+		{
+			/* Data Input for Speaker Path */
+			.port = 1,
+			.sink = &max98363_dp1
+		}
+	}
+};
+
+static void soundwire_max98363_fill_ssdt(const struct device *dev)
+{
+	struct drivers_soundwire_max98363_config *config = dev->chip_info;
+	const char *scope = acpi_device_scope(dev);
+	struct acpi_dp *dsd;
+
+	if (!scope)
+		return;
+
+	acpigen_write_scope(scope);
+	acpigen_write_device(acpi_device_name(dev));
+
+	/* Set codec address IDs. */
+	max98363_address.link_id = dev->path.generic.id;
+	max98363_address.unique_id = dev->path.generic.subid;
+
+	acpigen_write_ADR_soundwire_device(&max98363_address);
+	acpigen_write_name_string("_DDN", config->desc ? : dev->chip_ops->name);
+	acpigen_write_STA(acpi_device_status(dev));
+
+	dsd = acpi_dp_new_table("_DSD");
+	soundwire_gen_codec(dsd, &max98363_codec, NULL);
+	acpi_dp_write(dsd);
+
+	acpigen_pop_len(); /* Device */
+	acpigen_pop_len(); /* Scope */
+}
+
+static const char *soundwire_max98363_acpi_name(const struct device *dev)
+{
+	struct drivers_soundwire_max98363_config *config = dev->chip_info;
+	if (config->acpi_name[0] != 0)
+		return config->acpi_name;
+	snprintf(config->acpi_name, sizeof(config->acpi_name), "SW%1X%1X",
+		 dev->path.generic.id, dev->path.generic.subid);
+	return config->acpi_name;
+}
+
+static struct device_operations soundwire_max98363_ops = {
+	.read_resources		= noop_read_resources,
+	.set_resources		= noop_set_resources,
+	.acpi_name		= soundwire_max98363_acpi_name,
+	.acpi_fill_ssdt		= soundwire_max98363_fill_ssdt,
+};
+
+static void soundwire_max98363_enable(struct device *dev)
+{
+	dev->ops = &soundwire_max98363_ops;
+}
+
+struct chip_operations drivers_soundwire_max98363_ops = {
+	CHIP_NAME("Maxim MAX98363 SoundWire Codec")
+	.enable_dev = soundwire_max98363_enable
+};
diff --git a/src/include/mipi/ids.h b/src/include/mipi/ids.h
index 982e6e1..a1d1f49 100644
--- a/src/include/mipi/ids.h
+++ b/src/include/mipi/ids.h
@@ -25,5 +25,6 @@
 
 #define MIPI_MFG_ID_MAXIM			0x019f
 #define MIPI_DEV_ID_MAXIM_MAX98373		0x8373
+#define MIPI_DEV_ID_MAXIM_MAX98363		0x8363
 
 #endif /* __MIPI_IDS_H__ */