Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/soundwire/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  amd_init.c   Sprache: C

 
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
 * SoundWire AMD Manager Initialize routines
 *
 * Initializes and creates SDW devices based on ACPI and Hardware values
 *
 * Copyright 2024 Advanced Micro Devices, Inc.
 */


#include <linux/acpi.h>
#include <linux/cleanup.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>

#include "amd_init.h"

#define ACP_PAD_PULLDOWN_CTRL    0x0001448
#define ACP_SW_PAD_KEEPER_EN    0x0001454
#define AMD_SDW0_PAD_CTRL_MASK    0x60
#define AMD_SDW1_PAD_CTRL_MASK    5
#define AMD_SDW_PAD_CTRL_MASK  (AMD_SDW0_PAD_CTRL_MASK | AMD_SDW1_PAD_CTRL_MASK)
#define AMD_SDW0_PAD_EN     1
#define AMD_SDW1_PAD_EN     0x10
#define AMD_SDW_PAD_EN   (AMD_SDW0_PAD_EN | AMD_SDW1_PAD_EN)

static int amd_enable_sdw_pads(void __iomem *mmio, u32 link_mask, struct device *dev)
{
 u32 pad_keeper_en, pad_pulldown_ctrl_mask;

 switch (link_mask) {
 case 1:
  pad_keeper_en = AMD_SDW0_PAD_EN;
  pad_pulldown_ctrl_mask = AMD_SDW0_PAD_CTRL_MASK;
  break;
 case 2:
  pad_keeper_en = AMD_SDW1_PAD_EN;
  pad_pulldown_ctrl_mask = AMD_SDW1_PAD_CTRL_MASK;
  break;
 case 3:
  pad_keeper_en = AMD_SDW_PAD_EN;
  pad_pulldown_ctrl_mask = AMD_SDW_PAD_CTRL_MASK;
  break;
 default:
  dev_err(dev, "No SDW Links are enabled\n");
  return -ENODEV;
 }

 amd_updatel(mmio, ACP_SW_PAD_KEEPER_EN, pad_keeper_en, pad_keeper_en);
 amd_updatel(mmio, ACP_PAD_PULLDOWN_CTRL, pad_pulldown_ctrl_mask, 0);

 return 0;
}

static int sdw_amd_cleanup(struct sdw_amd_ctx *ctx)
{
 int i;

 for (i = 0; i < ctx->count; i++) {
  if (!(ctx->link_mask & BIT(i)))
   continue;
  platform_device_unregister(ctx->pdev[i]);
 }

 return 0;
}

static struct sdw_amd_ctx *sdw_amd_probe_controller(struct sdw_amd_res *res)
{
 struct sdw_amd_ctx *ctx;
 struct acpi_device *adev;
 struct acp_sdw_pdata sdw_pdata[2];
 struct platform_device_info pdevinfo[2];
 u32 link_mask;
 int count, index;
 int ret;

 if (!res)
  return NULL;

 adev = acpi_fetch_acpi_dev(res->handle);
 if (!adev)
  return NULL;

 if (!res->count)
  return NULL;

 count = res->count;
 dev_dbg(&adev->dev, "Creating %d SDW Link devices\n", count);
 ret = amd_enable_sdw_pads(res->mmio_base, res->link_mask, res->parent);
 if (ret)
  return NULL;

 /*
 * we need to alloc/free memory manually and can't use devm:
 * this routine may be called from a workqueue, and not from
 * the parent .probe.
 * If devm_ was used, the memory might never be freed on errors.
 */

 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
 if (!ctx)
  return NULL;

 ctx->count = count;
 ctx->link_mask = res->link_mask;
 struct resource *sdw_res __free(kfree) = kzalloc(sizeof(*sdw_res),
        GFP_KERNEL);
 if (!sdw_res) {
  kfree(ctx);
  return NULL;
 }
 sdw_res->flags = IORESOURCE_MEM;
 sdw_res->start = res->addr;
 sdw_res->end = res->addr + res->reg_range;
 memset(&pdevinfo, 0, sizeof(pdevinfo));
 link_mask = ctx->link_mask;
 for (index = 0; index < count; index++) {
  if (!(link_mask & BIT(index)))
   continue;

  sdw_pdata[index].instance = index;
  sdw_pdata[index].acp_sdw_lock = res->acp_lock;
  sdw_pdata[index].acp_rev = res->acp_rev;
  pdevinfo[index].name = "amd_sdw_manager";
  pdevinfo[index].id = index;
  pdevinfo[index].parent = res->parent;
  pdevinfo[index].num_res = 1;
  pdevinfo[index].res = sdw_res;
  pdevinfo[index].data = &sdw_pdata[index];
  pdevinfo[index].size_data = sizeof(struct acp_sdw_pdata);
  pdevinfo[index].fwnode = acpi_fwnode_handle(adev);
  ctx->pdev[index] = platform_device_register_full(&pdevinfo[index]);
  if (IS_ERR(ctx->pdev[index]))
   goto err;
 }
 return ctx;
err:
 while (index--) {
  if (!(link_mask & BIT(index)))
   continue;

  platform_device_unregister(ctx->pdev[index]);
 }

 kfree(ctx);
 return NULL;
}

static int sdw_amd_startup(struct sdw_amd_ctx *ctx)
{
 struct amd_sdw_manager *amd_manager;
 int i, ret;

 /* Startup SDW Manager devices */
 for (i = 0; i < ctx->count; i++) {
  if (!(ctx->link_mask & BIT(i)))
   continue;
  amd_manager = dev_get_drvdata(&ctx->pdev[i]->dev);
  ret = amd_sdw_manager_start(amd_manager);
  if (ret)
   return ret;
 }

 return 0;
}

int sdw_amd_probe(struct sdw_amd_res *res, struct sdw_amd_ctx **sdw_ctx)
{
 *sdw_ctx = sdw_amd_probe_controller(res);
 if (!*sdw_ctx)
  return -ENODEV;

 return sdw_amd_startup(*sdw_ctx);
}
EXPORT_SYMBOL_NS(sdw_amd_probe, "SOUNDWIRE_AMD_INIT");

void sdw_amd_exit(struct sdw_amd_ctx *ctx)
{
 sdw_amd_cleanup(ctx);
 kfree(ctx->peripherals);
 kfree(ctx);
}
EXPORT_SYMBOL_NS(sdw_amd_exit, "SOUNDWIRE_AMD_INIT");

int sdw_amd_get_slave_info(struct sdw_amd_ctx *ctx)
{
 struct amd_sdw_manager *amd_manager;
 struct sdw_bus *bus;
 struct sdw_slave *slave;
 struct list_head *node;
 int index;
 int i = 0;
 int num_slaves = 0;

 for (index = 0; index < ctx->count; index++) {
  if (!(ctx->link_mask & BIT(index)))
   continue;
  amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
  if (!amd_manager)
   return -ENODEV;
  bus = &amd_manager->bus;
  /* Calculate number of slaves */
  list_for_each(node, &bus->slaves)
   num_slaves++;
 }

 ctx->peripherals = kmalloc(struct_size(ctx->peripherals, array, num_slaves),
       GFP_KERNEL);
 if (!ctx->peripherals)
  return -ENOMEM;
 ctx->peripherals->num_peripherals = num_slaves;
 for (index = 0; index < ctx->count; index++) {
  if (!(ctx->link_mask & BIT(index)))
   continue;
  amd_manager = dev_get_drvdata(&ctx->pdev[index]->dev);
  if (amd_manager) {
   bus = &amd_manager->bus;
   list_for_each_entry(slave, &bus->slaves, node) {
    ctx->peripherals->array[i] = slave;
    i++;
   }
  }
 }
 return 0;
}
EXPORT_SYMBOL_NS(sdw_amd_get_slave_info, "SOUNDWIRE_AMD_INIT");

MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
MODULE_DESCRIPTION("AMD SoundWire Init Library");
MODULE_LICENSE("Dual BSD/GPL");

Messung V0.5
C=97 H=92 G=94

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.