clear-pkgs-linux-iot-lts2018/0166-Add-facility-to-load-R...

326 lines
8.9 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Guneshwor Singh <guneshwor.o.singh@intel.com>
Date: Tue, 17 Nov 2015 05:27:39 +0530
Subject: [PATCH] Add facility to load ROM via debugfs
For FPGA images without ROM inbuilt, this adds feature to
load the ROM manually via debugfs
Change-Id: I653ffd6d6ee735403d0137af33dc2ad701b478ed
Signed-off-by: Guneshwor Singh <guneshwor.o.singh@intel.com>
Reviewed-on:
Reviewed-by: Shah, Hardik T <hardik.t.shah@intel.com>
Tested-by: Shah, Hardik T <hardik.t.shah@intel.com>
---
sound/soc/intel/Makefile | 3 +
sound/soc/intel/fpga/Makefile | 4 +
sound/soc/intel/fpga/hda_intel_cnl_fpga.c | 274 ++++++++++++++++++++++
3 files changed, 281 insertions(+)
create mode 100644 sound/soc/intel/fpga/Makefile
create mode 100644 sound/soc/intel/fpga/hda_intel_cnl_fpga.c
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index 8160520fd74c..ece7c2b228d1 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -10,3 +10,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/
# Machine support
obj-$(CONFIG_SND_SOC) += boards/
+
+# FPGA support
+obj-$(CONFIG_SND_SOC_INTEL_CNL_FPGA) += fpga/
diff --git a/sound/soc/intel/fpga/Makefile b/sound/soc/intel/fpga/Makefile
new file mode 100644
index 000000000000..f434f7bcfd62
--- /dev/null
+++ b/sound/soc/intel/fpga/Makefile
@@ -0,0 +1,4 @@
+# for intel cnl fpga device
+snd-hda-intel-cnl-fpga-objs := hda_intel_cnl_fpga.o
+obj-$(CONFIG_SND_SOC_INTEL_CNL_FPGA) += snd-hda-intel-cnl-fpga.o
+
diff --git a/sound/soc/intel/fpga/hda_intel_cnl_fpga.c b/sound/soc/intel/fpga/hda_intel_cnl_fpga.c
new file mode 100644
index 000000000000..934a1a98b64a
--- /dev/null
+++ b/sound/soc/intel/fpga/hda_intel_cnl_fpga.c
@@ -0,0 +1,274 @@
+/*
+ * Intel HDA Cannonlake FPGA driver
+ *
+ * Copyright (C) 2014, Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define HDA_INTEL_CNL_FPGA_ROM_SIZE (16 * 1024)
+#define HDA_INTEL_CNL_FPGA_ROM_BAR_IDX 2
+#define HDA_INTEL_CNL_FPGA_ROM_KEY_OFFSET 0x805c
+#define HDA_INTEL_CNL_FPGA_ROM_MEM_OFFSET 0xc000
+
+struct hda_intel_cnl_fpga_dev {
+ void __iomem *rom_mem_base;
+ struct pci_dev *pdev;
+};
+
+static u32 hda_intel_cnl_fpga_readl(
+ struct hda_intel_cnl_fpga_dev *fpgadev,
+ u32 offset)
+{
+ u32 val;
+
+ val = readl((fpgadev)->rom_mem_base + offset);
+ printk(KERN_INFO "%s: TG@%x == %x\n", __func__, offset, val);
+ return val;
+}
+
+static void hda_intel_cnl_fpga_writel(
+ struct hda_intel_cnl_fpga_dev *fpgadev,
+ u32 offset,
+ u32 val)
+{
+ printk("%s: TG@%x <= %x\n", __func__, offset, val);
+ writel(val, (fpgadev)->rom_mem_base + offset);
+}
+
+static ssize_t hda_intel_cnl_fpga_rom_read(struct file *file,
+ char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct hda_intel_cnl_fpga_dev *fpgadev = file->private_data;
+ int i, size;
+ u32 *buf;
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_rom_read_in\n");
+
+ dev_dbg(&fpgadev->pdev->dev, "%s: pbuf: %p, *ppos: 0x%llx",
+ __func__, buffer, *ppos);
+
+ size = HDA_INTEL_CNL_FPGA_ROM_SIZE;
+
+ if (*ppos >= size)
+ return 0;
+ if (*ppos + count > size)
+ count = size - *ppos;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf) {
+ dev_dbg(&fpgadev->pdev->dev, " %s: kzalloc failed, aborting\n",
+ __func__);
+ return -ENOMEM;
+ }
+ size = size / sizeof(*buf);
+
+ printk(KERN_INFO "%s: bar: 0x%p\n", __func__, fpgadev->rom_mem_base);
+
+ for (i = 0; i < size; i++) {
+ hda_intel_cnl_fpga_writel(
+ fpgadev, HDA_INTEL_CNL_FPGA_ROM_KEY_OFFSET, 0);
+
+ buf[i] = hda_intel_cnl_fpga_readl(fpgadev,
+ HDA_INTEL_CNL_FPGA_ROM_MEM_OFFSET + i * sizeof(*buf));
+ }
+
+ if (copy_to_user(buffer, buf, count)) {
+ dev_err(&fpgadev->pdev->dev, " %s: copy_to_user failed, aborting\n",
+ __func__);
+ return -EFAULT;
+ }
+ kfree(buf);
+
+ *ppos += count;
+
+ dev_dbg(&fpgadev->pdev->dev, "%s: *ppos: 0x%llx, count: %zu",
+ __func__, *ppos, count);
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_rom_read_out\n");
+
+ return count;
+}
+
+static ssize_t hda_intel_cnl_fpga_rom_write(struct file *file,
+ const char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct hda_intel_cnl_fpga_dev *fpgadev = file->private_data;
+ int i, size;
+ u32 *buf;
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_rom_write_in\n");
+
+ dev_dbg(&fpgadev->pdev->dev, "%s: pbuf: %p, *ppos: 0x%llx",
+ __func__, buffer, *ppos);
+
+ size = HDA_INTEL_CNL_FPGA_ROM_SIZE;
+
+ if (*ppos >= size)
+ return 0;
+ if (*ppos + count > size)
+ count = size - *ppos;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf) {
+ dev_err(&fpgadev->pdev->dev, " %s: kzalloc failed, aborting\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ dev_err(&fpgadev->pdev->dev, " %s: copy_from_user failed, aborting\n",
+ __func__);
+ return -EFAULT;
+ }
+
+ size = size / sizeof(*buf);
+
+ for (i = 0; i < size; i++) {
+ hda_intel_cnl_fpga_writel(
+ fpgadev, HDA_INTEL_CNL_FPGA_ROM_KEY_OFFSET, 0);
+
+ hda_intel_cnl_fpga_writel(fpgadev,
+ HDA_INTEL_CNL_FPGA_ROM_MEM_OFFSET + i * sizeof(*buf),
+ buf[i]);
+ }
+
+ kfree(buf);
+ *ppos += count;
+
+ dev_dbg(&fpgadev->pdev->dev, "%s: *ppos: 0x%llx, count: %zu",
+ __func__, *ppos, count);
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_rom_write_out\n");
+
+ return count;
+}
+
+static const struct file_operations hda_intel_cnl_fpga_rom_fops = {
+ .owner = THIS_MODULE,
+ .open = simple_open,
+ .read = hda_intel_cnl_fpga_rom_read,
+ .write = hda_intel_cnl_fpga_rom_write,
+};
+
+static int hda_intel_cnl_fpga_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_id)
+{
+ struct hda_intel_cnl_fpga_dev *fpgadev;
+ int ret = 0;
+
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: pci_enable_device failed: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ fpgadev = kzalloc(sizeof(struct hda_intel_cnl_fpga_dev), GFP_KERNEL);
+ if (!fpgadev) {
+ dev_err(&pdev->dev, "%s: kzalloc failed, aborting.\n",
+ __func__);
+ ret = -ENOMEM;
+ goto err_alloc;
+ }
+
+ printk(KERN_INFO "%s: bar: 0, start 0x%p\n", __func__,
+ (void *)pci_resource_start(pdev, 0));
+ printk(KERN_INFO "%s: bar: 0, flags 0x%lx\n", __func__,
+ pci_resource_flags(pdev, 0));
+ printk(KERN_INFO "%s: bar: 1, start 0x%p\n", __func__,
+ (void *)pci_resource_start(pdev, 1));
+ printk(KERN_INFO "%s: bar: 1, flags 0x%lx\n", __func__,
+ pci_resource_flags(pdev, 1));
+ printk(KERN_INFO "%s: bar: 2, start 0x%p\n", __func__,
+ (void *)pci_resource_start(pdev, 2));
+ printk(KERN_INFO "%s: bar: 2, flags 0x%lx\n", __func__,
+ pci_resource_flags(pdev, 2));
+ printk(KERN_INFO "%s: bar: 3, start 0x%p\n", __func__,
+ (void *)pci_resource_start(pdev, 3));
+ printk(KERN_INFO "%s: bar: 3, flags 0x%lx\n", __func__,
+ pci_resource_flags(pdev, 3));
+
+ fpgadev->rom_mem_base
+ = pci_ioremap_bar(pdev, HDA_INTEL_CNL_FPGA_ROM_BAR_IDX);
+ printk("%s: bar: 0x%p\n", __func__, fpgadev->rom_mem_base);
+ if (!fpgadev->rom_mem_base) {
+ dev_err(&pdev->dev, "%s: ioremap failed, aborting\n",
+ __func__);
+ ret = -ENXIO;
+ goto err_map;
+ }
+
+ fpgadev->pdev = pdev;
+
+ pci_set_drvdata(pdev, fpgadev);
+
+ if (!debugfs_create_file("cnl_oed_rom", 0644, NULL,
+ fpgadev, &hda_intel_cnl_fpga_rom_fops)) {
+ dev_err(&pdev->dev, "%s: cannot create debugfs entry.\n",
+ __func__);
+ ret = -ENODEV;
+ goto err_map;
+ }
+
+ return ret;
+
+err_map:
+ if (fpgadev->rom_mem_base) {
+ iounmap(fpgadev->rom_mem_base);
+ fpgadev->rom_mem_base = NULL;
+ }
+ kfree(fpgadev);
+err_alloc:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void hda_intel_cnl_fpga_remove(struct pci_dev *pdev)
+{
+ struct hda_intel_cnl_fpga_dev *fpgadev = pci_get_drvdata(pdev);
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_remove_in");
+ /* unmap PCI memory space, mapped during device init. */
+ if (fpgadev->rom_mem_base) {
+ iounmap(fpgadev->rom_mem_base);
+ fpgadev->rom_mem_base = NULL;
+ }
+ pci_disable_device(pdev);
+ kfree(fpgadev);
+
+ printk(KERN_INFO "hda_intel_cnl_fpga_remove_out");
+}
+
+/* PCI IDs */
+static const struct pci_device_id hda_intel_cnl_fpga_ids[] = {
+ { PCI_DEVICE(0x8086, 0xF501) },
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, hda_intel_cnl_fpga_ids);
+
+/* pci_driver definition */
+static struct pci_driver hda_intel_cnl_fpga_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = hda_intel_cnl_fpga_ids,
+ .probe = hda_intel_cnl_fpga_probe,
+ .remove = hda_intel_cnl_fpga_remove,
+};
+
+module_pci_driver(hda_intel_cnl_fpga_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Intel HDA CNL FPGA driver");
--
https://clearlinux.org