| .. | .. | 
|---|
| 8 | 8 | */ | 
|---|
| 9 | 9 |  | 
|---|
| 10 | 10 | #include <linux/acpi.h> | 
|---|
|  | 11 | +#include <linux/export.h> | 
|---|
|  | 12 | +#include <linux/interrupt.h> | 
|---|
|  | 13 | +#include <linux/io.h> | 
|---|
|  | 14 | +#include <linux/module.h> | 
|---|
| 11 | 15 | #include <linux/platform_device.h> | 
|---|
|  | 16 | +#include <linux/pm_runtime.h> | 
|---|
| 12 | 17 | #include <linux/soundwire/sdw_intel.h> | 
|---|
|  | 18 | +#include "cadence_master.h" | 
|---|
| 13 | 19 | #include "intel.h" | 
|---|
| 14 | 20 |  | 
|---|
|  | 21 | +#define SDW_LINK_TYPE		4 /* from Intel ACPI documentation */ | 
|---|
| 15 | 22 | #define SDW_MAX_LINKS		4 | 
|---|
| 16 | 23 | #define SDW_SHIM_LCAP		0x0 | 
|---|
| 17 | 24 | #define SDW_SHIM_BASE		0x2C000 | 
|---|
| .. | .. | 
|---|
| 19 | 26 | #define SDW_LINK_BASE		0x30000 | 
|---|
| 20 | 27 | #define SDW_LINK_SIZE		0x10000 | 
|---|
| 21 | 28 |  | 
|---|
| 22 |  | -struct sdw_link_data { | 
|---|
| 23 |  | -	struct sdw_intel_link_res res; | 
|---|
| 24 |  | -	struct platform_device *pdev; | 
|---|
| 25 |  | -}; | 
|---|
|  | 29 | +static int ctrl_link_mask; | 
|---|
|  | 30 | +module_param_named(sdw_link_mask, ctrl_link_mask, int, 0444); | 
|---|
|  | 31 | +MODULE_PARM_DESC(sdw_link_mask, "Intel link mask (one bit per link)"); | 
|---|
| 26 | 32 |  | 
|---|
| 27 |  | -struct sdw_intel_ctx { | 
|---|
| 28 |  | -	int count; | 
|---|
| 29 |  | -	struct sdw_link_data *links; | 
|---|
| 30 |  | -}; | 
|---|
| 31 |  | - | 
|---|
| 32 |  | -static int sdw_intel_cleanup_pdev(struct sdw_intel_ctx *ctx) | 
|---|
|  | 33 | +static bool is_link_enabled(struct fwnode_handle *fw_node, int i) | 
|---|
| 33 | 34 | { | 
|---|
| 34 |  | -	struct sdw_link_data *link = ctx->links; | 
|---|
|  | 35 | +	struct fwnode_handle *link; | 
|---|
|  | 36 | +	char name[32]; | 
|---|
|  | 37 | +	u32 quirk_mask = 0; | 
|---|
|  | 38 | + | 
|---|
|  | 39 | +	/* Find master handle */ | 
|---|
|  | 40 | +	snprintf(name, sizeof(name), | 
|---|
|  | 41 | +		 "mipi-sdw-link-%d-subproperties", i); | 
|---|
|  | 42 | + | 
|---|
|  | 43 | +	link = fwnode_get_named_child_node(fw_node, name); | 
|---|
|  | 44 | +	if (!link) | 
|---|
|  | 45 | +		return false; | 
|---|
|  | 46 | + | 
|---|
|  | 47 | +	fwnode_property_read_u32(link, | 
|---|
|  | 48 | +				 "intel-quirk-mask", | 
|---|
|  | 49 | +				 &quirk_mask); | 
|---|
|  | 50 | + | 
|---|
|  | 51 | +	if (quirk_mask & SDW_INTEL_QUIRK_MASK_BUS_DISABLE) | 
|---|
|  | 52 | +		return false; | 
|---|
|  | 53 | + | 
|---|
|  | 54 | +	return true; | 
|---|
|  | 55 | +} | 
|---|
|  | 56 | + | 
|---|
|  | 57 | +static int sdw_intel_cleanup(struct sdw_intel_ctx *ctx) | 
|---|
|  | 58 | +{ | 
|---|
|  | 59 | +	struct sdw_intel_link_res *link = ctx->links; | 
|---|
|  | 60 | +	u32 link_mask; | 
|---|
| 35 | 61 | int i; | 
|---|
| 36 | 62 |  | 
|---|
| 37 | 63 | if (!link) | 
|---|
| 38 | 64 | return 0; | 
|---|
| 39 | 65 |  | 
|---|
| 40 |  | -	for (i = 0; i < ctx->count; i++) { | 
|---|
| 41 |  | -		if (link->pdev) | 
|---|
| 42 |  | -			platform_device_unregister(link->pdev); | 
|---|
| 43 |  | -		link++; | 
|---|
| 44 |  | -	} | 
|---|
|  | 66 | +	link_mask = ctx->link_mask; | 
|---|
| 45 | 67 |  | 
|---|
| 46 |  | -	kfree(ctx->links); | 
|---|
| 47 |  | -	ctx->links = NULL; | 
|---|
|  | 68 | +	for (i = 0; i < ctx->count; i++, link++) { | 
|---|
|  | 69 | +		if (!(link_mask & BIT(i))) | 
|---|
|  | 70 | +			continue; | 
|---|
|  | 71 | + | 
|---|
|  | 72 | +		if (link->pdev) { | 
|---|
|  | 73 | +			pm_runtime_disable(&link->pdev->dev); | 
|---|
|  | 74 | +			platform_device_unregister(link->pdev); | 
|---|
|  | 75 | +		} | 
|---|
|  | 76 | + | 
|---|
|  | 77 | +		if (!link->clock_stop_quirks) | 
|---|
|  | 78 | +			pm_runtime_put_noidle(link->dev); | 
|---|
|  | 79 | +	} | 
|---|
| 48 | 80 |  | 
|---|
| 49 | 81 | return 0; | 
|---|
| 50 | 82 | } | 
|---|
| 51 | 83 |  | 
|---|
| 52 |  | -static struct sdw_intel_ctx | 
|---|
| 53 |  | -*sdw_intel_add_controller(struct sdw_intel_res *res) | 
|---|
|  | 84 | +static int | 
|---|
|  | 85 | +sdw_intel_scan_controller(struct sdw_intel_acpi_info *info) | 
|---|
| 54 | 86 | { | 
|---|
| 55 |  | -	struct platform_device_info pdevinfo; | 
|---|
| 56 |  | -	struct platform_device *pdev; | 
|---|
| 57 |  | -	struct sdw_link_data *link; | 
|---|
| 58 |  | -	struct sdw_intel_ctx *ctx; | 
|---|
| 59 | 87 | struct acpi_device *adev; | 
|---|
| 60 | 88 | int ret, i; | 
|---|
| 61 | 89 | u8 count; | 
|---|
| 62 |  | -	u32 caps; | 
|---|
| 63 | 90 |  | 
|---|
| 64 |  | -	if (acpi_bus_get_device(res->handle, &adev)) | 
|---|
| 65 |  | -		return NULL; | 
|---|
|  | 91 | +	if (acpi_bus_get_device(info->handle, &adev)) | 
|---|
|  | 92 | +		return -EINVAL; | 
|---|
| 66 | 93 |  | 
|---|
| 67 | 94 | /* Found controller, find links supported */ | 
|---|
| 68 | 95 | count = 0; | 
|---|
| 69 | 96 | ret = fwnode_property_read_u8_array(acpi_fwnode_handle(adev), | 
|---|
| 70 |  | -				  "mipi-sdw-master-count", &count, 1); | 
|---|
|  | 97 | +					    "mipi-sdw-master-count", &count, 1); | 
|---|
| 71 | 98 |  | 
|---|
| 72 |  | -	/* Don't fail on error, continue and use hw value */ | 
|---|
|  | 99 | +	/* | 
|---|
|  | 100 | +	 * In theory we could check the number of links supported in | 
|---|
|  | 101 | +	 * hardware, but in that step we cannot assume SoundWire IP is | 
|---|
|  | 102 | +	 * powered. | 
|---|
|  | 103 | +	 * | 
|---|
|  | 104 | +	 * In addition, if the BIOS doesn't even provide this | 
|---|
|  | 105 | +	 * 'master-count' property then all the inits based on link | 
|---|
|  | 106 | +	 * masks will fail as well. | 
|---|
|  | 107 | +	 * | 
|---|
|  | 108 | +	 * We will check the hardware capabilities in the startup() step | 
|---|
|  | 109 | +	 */ | 
|---|
|  | 110 | + | 
|---|
| 73 | 111 | if (ret) { | 
|---|
| 74 | 112 | dev_err(&adev->dev, | 
|---|
| 75 | 113 | "Failed to read mipi-sdw-master-count: %d\n", ret); | 
|---|
| 76 |  | -		count = SDW_MAX_LINKS; | 
|---|
|  | 114 | +		return -EINVAL; | 
|---|
| 77 | 115 | } | 
|---|
| 78 |  | - | 
|---|
| 79 |  | -	/* Check SNDWLCAP.LCOUNT */ | 
|---|
| 80 |  | -	caps = ioread32(res->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); | 
|---|
| 81 |  | - | 
|---|
| 82 |  | -	/* Check HW supported vs property value and use min of two */ | 
|---|
| 83 |  | -	count = min_t(u8, caps, count); | 
|---|
| 84 | 116 |  | 
|---|
| 85 | 117 | /* Check count is within bounds */ | 
|---|
| 86 | 118 | if (count > SDW_MAX_LINKS) { | 
|---|
| 87 | 119 | dev_err(&adev->dev, "Link count %d exceeds max %d\n", | 
|---|
| 88 |  | -						count, SDW_MAX_LINKS); | 
|---|
| 89 |  | -		return NULL; | 
|---|
|  | 120 | +			count, SDW_MAX_LINKS); | 
|---|
|  | 121 | +		return -EINVAL; | 
|---|
| 90 | 122 | } | 
|---|
| 91 | 123 |  | 
|---|
|  | 124 | +	if (!count) { | 
|---|
|  | 125 | +		dev_warn(&adev->dev, "No SoundWire links detected\n"); | 
|---|
|  | 126 | +		return -EINVAL; | 
|---|
|  | 127 | +	} | 
|---|
|  | 128 | +	dev_dbg(&adev->dev, "ACPI reports %d SDW Link devices\n", count); | 
|---|
|  | 129 | + | 
|---|
|  | 130 | +	info->count = count; | 
|---|
|  | 131 | +	info->link_mask = 0; | 
|---|
|  | 132 | + | 
|---|
|  | 133 | +	for (i = 0; i < count; i++) { | 
|---|
|  | 134 | +		if (ctrl_link_mask && !(ctrl_link_mask & BIT(i))) { | 
|---|
|  | 135 | +			dev_dbg(&adev->dev, | 
|---|
|  | 136 | +				"Link %d masked, will not be enabled\n", i); | 
|---|
|  | 137 | +			continue; | 
|---|
|  | 138 | +		} | 
|---|
|  | 139 | + | 
|---|
|  | 140 | +		if (!is_link_enabled(acpi_fwnode_handle(adev), i)) { | 
|---|
|  | 141 | +			dev_dbg(&adev->dev, | 
|---|
|  | 142 | +				"Link %d not selected in firmware\n", i); | 
|---|
|  | 143 | +			continue; | 
|---|
|  | 144 | +		} | 
|---|
|  | 145 | + | 
|---|
|  | 146 | +		info->link_mask |= BIT(i); | 
|---|
|  | 147 | +	} | 
|---|
|  | 148 | + | 
|---|
|  | 149 | +	return 0; | 
|---|
|  | 150 | +} | 
|---|
|  | 151 | + | 
|---|
|  | 152 | +#define HDA_DSP_REG_ADSPIC2             (0x10) | 
|---|
|  | 153 | +#define HDA_DSP_REG_ADSPIS2             (0x14) | 
|---|
|  | 154 | +#define HDA_DSP_REG_ADSPIC2_SNDW        BIT(5) | 
|---|
|  | 155 | + | 
|---|
|  | 156 | +/** | 
|---|
|  | 157 | + * sdw_intel_enable_irq() - enable/disable Intel SoundWire IRQ | 
|---|
|  | 158 | + * @mmio_base: The mmio base of the control register | 
|---|
|  | 159 | + * @enable: true if enable | 
|---|
|  | 160 | + */ | 
|---|
|  | 161 | +void sdw_intel_enable_irq(void __iomem *mmio_base, bool enable) | 
|---|
|  | 162 | +{ | 
|---|
|  | 163 | +	u32 val; | 
|---|
|  | 164 | + | 
|---|
|  | 165 | +	val = readl(mmio_base + HDA_DSP_REG_ADSPIC2); | 
|---|
|  | 166 | + | 
|---|
|  | 167 | +	if (enable) | 
|---|
|  | 168 | +		val |= HDA_DSP_REG_ADSPIC2_SNDW; | 
|---|
|  | 169 | +	else | 
|---|
|  | 170 | +		val &= ~HDA_DSP_REG_ADSPIC2_SNDW; | 
|---|
|  | 171 | + | 
|---|
|  | 172 | +	writel(val, mmio_base + HDA_DSP_REG_ADSPIC2); | 
|---|
|  | 173 | +} | 
|---|
|  | 174 | +EXPORT_SYMBOL_NS(sdw_intel_enable_irq, SOUNDWIRE_INTEL_INIT); | 
|---|
|  | 175 | + | 
|---|
|  | 176 | +irqreturn_t sdw_intel_thread(int irq, void *dev_id) | 
|---|
|  | 177 | +{ | 
|---|
|  | 178 | +	struct sdw_intel_ctx *ctx = dev_id; | 
|---|
|  | 179 | +	struct sdw_intel_link_res *link; | 
|---|
|  | 180 | + | 
|---|
|  | 181 | +	list_for_each_entry(link, &ctx->link_list, list) | 
|---|
|  | 182 | +		sdw_cdns_irq(irq, link->cdns); | 
|---|
|  | 183 | + | 
|---|
|  | 184 | +	sdw_intel_enable_irq(ctx->mmio_base, true); | 
|---|
|  | 185 | +	return IRQ_HANDLED; | 
|---|
|  | 186 | +} | 
|---|
|  | 187 | +EXPORT_SYMBOL_NS(sdw_intel_thread, SOUNDWIRE_INTEL_INIT); | 
|---|
|  | 188 | + | 
|---|
|  | 189 | +static struct sdw_intel_ctx | 
|---|
|  | 190 | +*sdw_intel_probe_controller(struct sdw_intel_res *res) | 
|---|
|  | 191 | +{ | 
|---|
|  | 192 | +	struct platform_device_info pdevinfo; | 
|---|
|  | 193 | +	struct platform_device *pdev; | 
|---|
|  | 194 | +	struct sdw_intel_link_res *link; | 
|---|
|  | 195 | +	struct sdw_intel_ctx *ctx; | 
|---|
|  | 196 | +	struct acpi_device *adev; | 
|---|
|  | 197 | +	struct sdw_slave *slave; | 
|---|
|  | 198 | +	struct list_head *node; | 
|---|
|  | 199 | +	struct sdw_bus *bus; | 
|---|
|  | 200 | +	u32 link_mask; | 
|---|
|  | 201 | +	int num_slaves = 0; | 
|---|
|  | 202 | +	int count; | 
|---|
|  | 203 | +	int i; | 
|---|
|  | 204 | + | 
|---|
|  | 205 | +	if (!res) | 
|---|
|  | 206 | +		return NULL; | 
|---|
|  | 207 | + | 
|---|
|  | 208 | +	if (acpi_bus_get_device(res->handle, &adev)) | 
|---|
|  | 209 | +		return NULL; | 
|---|
|  | 210 | + | 
|---|
|  | 211 | +	if (!res->count) | 
|---|
|  | 212 | +		return NULL; | 
|---|
|  | 213 | + | 
|---|
|  | 214 | +	count = res->count; | 
|---|
| 92 | 215 | dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count); | 
|---|
| 93 | 216 |  | 
|---|
| 94 |  | -	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | 
|---|
|  | 217 | +	ctx = devm_kzalloc(&adev->dev, sizeof(*ctx), GFP_KERNEL); | 
|---|
| 95 | 218 | if (!ctx) | 
|---|
| 96 | 219 | return NULL; | 
|---|
| 97 | 220 |  | 
|---|
| 98 | 221 | ctx->count = count; | 
|---|
| 99 |  | -	ctx->links = kcalloc(ctx->count, sizeof(*ctx->links), GFP_KERNEL); | 
|---|
|  | 222 | +	ctx->links = devm_kcalloc(&adev->dev, ctx->count, | 
|---|
|  | 223 | +				  sizeof(*ctx->links), GFP_KERNEL); | 
|---|
| 100 | 224 | if (!ctx->links) | 
|---|
| 101 |  | -		goto link_err; | 
|---|
|  | 225 | +		return NULL; | 
|---|
|  | 226 | + | 
|---|
|  | 227 | +	ctx->count = count; | 
|---|
|  | 228 | +	ctx->mmio_base = res->mmio_base; | 
|---|
|  | 229 | +	ctx->link_mask = res->link_mask; | 
|---|
|  | 230 | +	ctx->handle = res->handle; | 
|---|
|  | 231 | +	mutex_init(&ctx->shim_lock); | 
|---|
| 102 | 232 |  | 
|---|
| 103 | 233 | link = ctx->links; | 
|---|
|  | 234 | +	link_mask = ctx->link_mask; | 
|---|
|  | 235 | + | 
|---|
|  | 236 | +	INIT_LIST_HEAD(&ctx->link_list); | 
|---|
| 104 | 237 |  | 
|---|
| 105 | 238 | /* Create SDW Master devices */ | 
|---|
| 106 |  | -	for (i = 0; i < count; i++) { | 
|---|
|  | 239 | +	for (i = 0; i < count; i++, link++) { | 
|---|
|  | 240 | +		if (!(link_mask & BIT(i))) { | 
|---|
|  | 241 | +			dev_dbg(&adev->dev, | 
|---|
|  | 242 | +				"Link %d masked, will not be enabled\n", i); | 
|---|
|  | 243 | +			continue; | 
|---|
|  | 244 | +		} | 
|---|
| 107 | 245 |  | 
|---|
| 108 |  | -		link->res.irq = res->irq; | 
|---|
| 109 |  | -		link->res.registers = res->mmio_base + SDW_LINK_BASE | 
|---|
| 110 |  | -					+ (SDW_LINK_SIZE * i); | 
|---|
| 111 |  | -		link->res.shim = res->mmio_base + SDW_SHIM_BASE; | 
|---|
| 112 |  | -		link->res.alh = res->mmio_base + SDW_ALH_BASE; | 
|---|
|  | 246 | +		link->mmio_base = res->mmio_base; | 
|---|
|  | 247 | +		link->registers = res->mmio_base + SDW_LINK_BASE | 
|---|
|  | 248 | +			+ (SDW_LINK_SIZE * i); | 
|---|
|  | 249 | +		link->shim = res->mmio_base + SDW_SHIM_BASE; | 
|---|
|  | 250 | +		link->alh = res->mmio_base + SDW_ALH_BASE; | 
|---|
| 113 | 251 |  | 
|---|
| 114 |  | -		link->res.ops = res->ops; | 
|---|
| 115 |  | -		link->res.arg = res->arg; | 
|---|
|  | 252 | +		link->ops = res->ops; | 
|---|
|  | 253 | +		link->dev = res->dev; | 
|---|
|  | 254 | + | 
|---|
|  | 255 | +		link->clock_stop_quirks = res->clock_stop_quirks; | 
|---|
|  | 256 | +		link->shim_lock = &ctx->shim_lock; | 
|---|
|  | 257 | +		link->shim_mask = &ctx->shim_mask; | 
|---|
|  | 258 | +		link->link_mask = link_mask; | 
|---|
| 116 | 259 |  | 
|---|
| 117 | 260 | memset(&pdevinfo, 0, sizeof(pdevinfo)); | 
|---|
| 118 | 261 |  | 
|---|
| 119 | 262 | pdevinfo.parent = res->parent; | 
|---|
| 120 |  | -		pdevinfo.name = "int-sdw"; | 
|---|
|  | 263 | +		pdevinfo.name = "intel-sdw"; | 
|---|
| 121 | 264 | pdevinfo.id = i; | 
|---|
| 122 | 265 | pdevinfo.fwnode = acpi_fwnode_handle(adev); | 
|---|
| 123 |  | -		pdevinfo.data = &link->res; | 
|---|
| 124 |  | -		pdevinfo.size_data = sizeof(link->res); | 
|---|
|  | 266 | +		pdevinfo.data = link; | 
|---|
|  | 267 | +		pdevinfo.size_data = sizeof(*link); | 
|---|
| 125 | 268 |  | 
|---|
| 126 | 269 | pdev = platform_device_register_full(&pdevinfo); | 
|---|
| 127 | 270 | if (IS_ERR(pdev)) { | 
|---|
| 128 | 271 | dev_err(&adev->dev, | 
|---|
| 129 | 272 | "platform device creation failed: %ld\n", | 
|---|
| 130 | 273 | PTR_ERR(pdev)); | 
|---|
| 131 |  | -			goto pdev_err; | 
|---|
|  | 274 | +			goto err; | 
|---|
| 132 | 275 | } | 
|---|
| 133 |  | - | 
|---|
| 134 | 276 | link->pdev = pdev; | 
|---|
| 135 |  | -		link++; | 
|---|
|  | 277 | +		link->cdns = platform_get_drvdata(pdev); | 
|---|
|  | 278 | + | 
|---|
|  | 279 | +		list_add_tail(&link->list, &ctx->link_list); | 
|---|
|  | 280 | +		bus = &link->cdns->bus; | 
|---|
|  | 281 | +		/* Calculate number of slaves */ | 
|---|
|  | 282 | +		list_for_each(node, &bus->slaves) | 
|---|
|  | 283 | +			num_slaves++; | 
|---|
|  | 284 | +	} | 
|---|
|  | 285 | + | 
|---|
|  | 286 | +	ctx->ids = devm_kcalloc(&adev->dev, num_slaves, | 
|---|
|  | 287 | +				sizeof(*ctx->ids), GFP_KERNEL); | 
|---|
|  | 288 | +	if (!ctx->ids) | 
|---|
|  | 289 | +		goto err; | 
|---|
|  | 290 | + | 
|---|
|  | 291 | +	ctx->num_slaves = num_slaves; | 
|---|
|  | 292 | +	i = 0; | 
|---|
|  | 293 | +	list_for_each_entry(link, &ctx->link_list, list) { | 
|---|
|  | 294 | +		bus = &link->cdns->bus; | 
|---|
|  | 295 | +		list_for_each_entry(slave, &bus->slaves, node) { | 
|---|
|  | 296 | +			ctx->ids[i].id = slave->id; | 
|---|
|  | 297 | +			ctx->ids[i].link_id = bus->link_id; | 
|---|
|  | 298 | +			i++; | 
|---|
|  | 299 | +		} | 
|---|
| 136 | 300 | } | 
|---|
| 137 | 301 |  | 
|---|
| 138 | 302 | return ctx; | 
|---|
| 139 | 303 |  | 
|---|
| 140 |  | -pdev_err: | 
|---|
| 141 |  | -	sdw_intel_cleanup_pdev(ctx); | 
|---|
| 142 |  | -link_err: | 
|---|
| 143 |  | -	kfree(ctx); | 
|---|
|  | 304 | +err: | 
|---|
|  | 305 | +	ctx->count = i; | 
|---|
|  | 306 | +	sdw_intel_cleanup(ctx); | 
|---|
| 144 | 307 | return NULL; | 
|---|
| 145 | 308 | } | 
|---|
| 146 | 309 |  | 
|---|
| 147 |  | -static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, | 
|---|
| 148 |  | -					void *cdata, void **return_value) | 
|---|
|  | 310 | +static int | 
|---|
|  | 311 | +sdw_intel_startup_controller(struct sdw_intel_ctx *ctx) | 
|---|
| 149 | 312 | { | 
|---|
| 150 |  | -	struct sdw_intel_res *res = cdata; | 
|---|
| 151 | 313 | struct acpi_device *adev; | 
|---|
|  | 314 | +	struct sdw_intel_link_res *link; | 
|---|
|  | 315 | +	u32 caps; | 
|---|
|  | 316 | +	u32 link_mask; | 
|---|
|  | 317 | +	int i; | 
|---|
|  | 318 | + | 
|---|
|  | 319 | +	if (acpi_bus_get_device(ctx->handle, &adev)) | 
|---|
|  | 320 | +		return -EINVAL; | 
|---|
|  | 321 | + | 
|---|
|  | 322 | +	/* Check SNDWLCAP.LCOUNT */ | 
|---|
|  | 323 | +	caps = ioread32(ctx->mmio_base + SDW_SHIM_BASE + SDW_SHIM_LCAP); | 
|---|
|  | 324 | +	caps &= GENMASK(2, 0); | 
|---|
|  | 325 | + | 
|---|
|  | 326 | +	/* Check HW supported vs property value */ | 
|---|
|  | 327 | +	if (caps < ctx->count) { | 
|---|
|  | 328 | +		dev_err(&adev->dev, | 
|---|
|  | 329 | +			"BIOS master count is larger than hardware capabilities\n"); | 
|---|
|  | 330 | +		return -EINVAL; | 
|---|
|  | 331 | +	} | 
|---|
|  | 332 | + | 
|---|
|  | 333 | +	if (!ctx->links) | 
|---|
|  | 334 | +		return -EINVAL; | 
|---|
|  | 335 | + | 
|---|
|  | 336 | +	link = ctx->links; | 
|---|
|  | 337 | +	link_mask = ctx->link_mask; | 
|---|
|  | 338 | + | 
|---|
|  | 339 | +	/* Startup SDW Master devices */ | 
|---|
|  | 340 | +	for (i = 0; i < ctx->count; i++, link++) { | 
|---|
|  | 341 | +		if (!(link_mask & BIT(i))) | 
|---|
|  | 342 | +			continue; | 
|---|
|  | 343 | + | 
|---|
|  | 344 | +		intel_master_startup(link->pdev); | 
|---|
|  | 345 | + | 
|---|
|  | 346 | +		if (!link->clock_stop_quirks) { | 
|---|
|  | 347 | +			/* | 
|---|
|  | 348 | +			 * we need to prevent the parent PCI device | 
|---|
|  | 349 | +			 * from entering pm_runtime suspend, so that | 
|---|
|  | 350 | +			 * power rails to the SoundWire IP are not | 
|---|
|  | 351 | +			 * turned off. | 
|---|
|  | 352 | +			 */ | 
|---|
|  | 353 | +			pm_runtime_get_noresume(link->dev); | 
|---|
|  | 354 | +		} | 
|---|
|  | 355 | +	} | 
|---|
|  | 356 | + | 
|---|
|  | 357 | +	return 0; | 
|---|
|  | 358 | +} | 
|---|
|  | 359 | + | 
|---|
|  | 360 | +static acpi_status sdw_intel_acpi_cb(acpi_handle handle, u32 level, | 
|---|
|  | 361 | +				     void *cdata, void **return_value) | 
|---|
|  | 362 | +{ | 
|---|
|  | 363 | +	struct sdw_intel_acpi_info *info = cdata; | 
|---|
|  | 364 | +	struct acpi_device *adev; | 
|---|
|  | 365 | +	acpi_status status; | 
|---|
|  | 366 | +	u64 adr; | 
|---|
|  | 367 | + | 
|---|
|  | 368 | +	status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &adr); | 
|---|
|  | 369 | +	if (ACPI_FAILURE(status)) | 
|---|
|  | 370 | +		return AE_OK; /* keep going */ | 
|---|
| 152 | 371 |  | 
|---|
| 153 | 372 | if (acpi_bus_get_device(handle, &adev)) { | 
|---|
| 154 | 373 | pr_err("%s: Couldn't find ACPI handle\n", __func__); | 
|---|
| 155 | 374 | return AE_NOT_FOUND; | 
|---|
| 156 | 375 | } | 
|---|
| 157 | 376 |  | 
|---|
| 158 |  | -	res->handle = handle; | 
|---|
| 159 |  | -	return AE_OK; | 
|---|
|  | 377 | +	info->handle = handle; | 
|---|
|  | 378 | + | 
|---|
|  | 379 | +	/* | 
|---|
|  | 380 | +	 * On some Intel platforms, multiple children of the HDAS | 
|---|
|  | 381 | +	 * device can be found, but only one of them is the SoundWire | 
|---|
|  | 382 | +	 * controller. The SNDW device is always exposed with | 
|---|
|  | 383 | +	 * Name(_ADR, 0x40000000), with bits 31..28 representing the | 
|---|
|  | 384 | +	 * SoundWire link so filter accordingly | 
|---|
|  | 385 | +	 */ | 
|---|
|  | 386 | +	if (FIELD_GET(GENMASK(31, 28), adr) != SDW_LINK_TYPE) | 
|---|
|  | 387 | +		return AE_OK; /* keep going */ | 
|---|
|  | 388 | + | 
|---|
|  | 389 | +	/* device found, stop namespace walk */ | 
|---|
|  | 390 | +	return AE_CTRL_TERMINATE; | 
|---|
| 160 | 391 | } | 
|---|
| 161 | 392 |  | 
|---|
| 162 | 393 | /** | 
|---|
| 163 |  | - * sdw_intel_init() - SoundWire Intel init routine | 
|---|
|  | 394 | + * sdw_intel_acpi_scan() - SoundWire Intel init routine | 
|---|
| 164 | 395 | * @parent_handle: ACPI parent handle | 
|---|
| 165 |  | - * @res: resource data | 
|---|
|  | 396 | + * @info: description of what firmware/DSDT tables expose | 
|---|
| 166 | 397 | * | 
|---|
| 167 |  | - * This scans the namespace and creates SoundWire link controller devices | 
|---|
| 168 |  | - * based on the info queried. | 
|---|
|  | 398 | + * This scans the namespace and queries firmware to figure out which | 
|---|
|  | 399 | + * links to enable. A follow-up use of sdw_intel_probe() and | 
|---|
|  | 400 | + * sdw_intel_startup() is required for creation of devices and bus | 
|---|
|  | 401 | + * startup | 
|---|
| 169 | 402 | */ | 
|---|
| 170 |  | -void *sdw_intel_init(acpi_handle *parent_handle, struct sdw_intel_res *res) | 
|---|
|  | 403 | +int sdw_intel_acpi_scan(acpi_handle *parent_handle, | 
|---|
|  | 404 | +			struct sdw_intel_acpi_info *info) | 
|---|
| 171 | 405 | { | 
|---|
| 172 | 406 | acpi_status status; | 
|---|
| 173 | 407 |  | 
|---|
|  | 408 | +	info->handle = NULL; | 
|---|
| 174 | 409 | status = acpi_walk_namespace(ACPI_TYPE_DEVICE, | 
|---|
| 175 |  | -					parent_handle, 1, | 
|---|
| 176 |  | -					sdw_intel_acpi_cb, | 
|---|
| 177 |  | -					NULL, res, NULL); | 
|---|
| 178 |  | -	if (ACPI_FAILURE(status)) | 
|---|
| 179 |  | -		return NULL; | 
|---|
|  | 410 | +				     parent_handle, 1, | 
|---|
|  | 411 | +				     sdw_intel_acpi_cb, | 
|---|
|  | 412 | +				     NULL, info, NULL); | 
|---|
|  | 413 | +	if (ACPI_FAILURE(status) || info->handle == NULL) | 
|---|
|  | 414 | +		return -ENODEV; | 
|---|
| 180 | 415 |  | 
|---|
| 181 |  | -	return sdw_intel_add_controller(res); | 
|---|
|  | 416 | +	return sdw_intel_scan_controller(info); | 
|---|
| 182 | 417 | } | 
|---|
| 183 |  | -EXPORT_SYMBOL(sdw_intel_init); | 
|---|
|  | 418 | +EXPORT_SYMBOL_NS(sdw_intel_acpi_scan, SOUNDWIRE_INTEL_INIT); | 
|---|
| 184 | 419 |  | 
|---|
| 185 | 420 | /** | 
|---|
|  | 421 | + * sdw_intel_probe() - SoundWire Intel probe routine | 
|---|
|  | 422 | + * @res: resource data | 
|---|
|  | 423 | + * | 
|---|
|  | 424 | + * This registers a platform device for each Master handled by the controller, | 
|---|
|  | 425 | + * and SoundWire Master and Slave devices will be created by the platform | 
|---|
|  | 426 | + * device probe. All the information necessary is stored in the context, and | 
|---|
|  | 427 | + * the res argument pointer can be freed after this step. | 
|---|
|  | 428 | + * This function will be called after sdw_intel_acpi_scan() by SOF probe. | 
|---|
|  | 429 | + */ | 
|---|
|  | 430 | +struct sdw_intel_ctx | 
|---|
|  | 431 | +*sdw_intel_probe(struct sdw_intel_res *res) | 
|---|
|  | 432 | +{ | 
|---|
|  | 433 | +	return sdw_intel_probe_controller(res); | 
|---|
|  | 434 | +} | 
|---|
|  | 435 | +EXPORT_SYMBOL_NS(sdw_intel_probe, SOUNDWIRE_INTEL_INIT); | 
|---|
|  | 436 | + | 
|---|
|  | 437 | +/** | 
|---|
|  | 438 | + * sdw_intel_startup() - SoundWire Intel startup | 
|---|
|  | 439 | + * @ctx: SoundWire context allocated in the probe | 
|---|
|  | 440 | + * | 
|---|
|  | 441 | + * Startup Intel SoundWire controller. This function will be called after | 
|---|
|  | 442 | + * Intel Audio DSP is powered up. | 
|---|
|  | 443 | + */ | 
|---|
|  | 444 | +int sdw_intel_startup(struct sdw_intel_ctx *ctx) | 
|---|
|  | 445 | +{ | 
|---|
|  | 446 | +	return sdw_intel_startup_controller(ctx); | 
|---|
|  | 447 | +} | 
|---|
|  | 448 | +EXPORT_SYMBOL_NS(sdw_intel_startup, SOUNDWIRE_INTEL_INIT); | 
|---|
|  | 449 | +/** | 
|---|
| 186 | 450 | * sdw_intel_exit() - SoundWire Intel exit | 
|---|
| 187 |  | - * @arg: callback context | 
|---|
|  | 451 | + * @ctx: SoundWire context allocated in the probe | 
|---|
| 188 | 452 | * | 
|---|
| 189 | 453 | * Delete the controller instances created and cleanup | 
|---|
| 190 | 454 | */ | 
|---|
| 191 |  | -void sdw_intel_exit(void *arg) | 
|---|
|  | 455 | +void sdw_intel_exit(struct sdw_intel_ctx *ctx) | 
|---|
| 192 | 456 | { | 
|---|
| 193 |  | -	struct sdw_intel_ctx *ctx = arg; | 
|---|
| 194 |  | - | 
|---|
| 195 |  | -	sdw_intel_cleanup_pdev(ctx); | 
|---|
| 196 |  | -	kfree(ctx); | 
|---|
|  | 457 | +	sdw_intel_cleanup(ctx); | 
|---|
| 197 | 458 | } | 
|---|
| 198 |  | -EXPORT_SYMBOL(sdw_intel_exit); | 
|---|
|  | 459 | +EXPORT_SYMBOL_NS(sdw_intel_exit, SOUNDWIRE_INTEL_INIT); | 
|---|
|  | 460 | + | 
|---|
|  | 461 | +void sdw_intel_process_wakeen_event(struct sdw_intel_ctx *ctx) | 
|---|
|  | 462 | +{ | 
|---|
|  | 463 | +	struct sdw_intel_link_res *link; | 
|---|
|  | 464 | +	u32 link_mask; | 
|---|
|  | 465 | +	int i; | 
|---|
|  | 466 | + | 
|---|
|  | 467 | +	if (!ctx->links) | 
|---|
|  | 468 | +		return; | 
|---|
|  | 469 | + | 
|---|
|  | 470 | +	link = ctx->links; | 
|---|
|  | 471 | +	link_mask = ctx->link_mask; | 
|---|
|  | 472 | + | 
|---|
|  | 473 | +	/* Startup SDW Master devices */ | 
|---|
|  | 474 | +	for (i = 0; i < ctx->count; i++, link++) { | 
|---|
|  | 475 | +		if (!(link_mask & BIT(i))) | 
|---|
|  | 476 | +			continue; | 
|---|
|  | 477 | + | 
|---|
|  | 478 | +		intel_master_process_wakeen_event(link->pdev); | 
|---|
|  | 479 | +	} | 
|---|
|  | 480 | +} | 
|---|
|  | 481 | +EXPORT_SYMBOL_NS(sdw_intel_process_wakeen_event, SOUNDWIRE_INTEL_INIT); | 
|---|
| 199 | 482 |  | 
|---|
| 200 | 483 | MODULE_LICENSE("Dual BSD/GPL"); | 
|---|
| 201 | 484 | MODULE_DESCRIPTION("Intel Soundwire Init Library"); | 
|---|