staging: most: dim2: rename module
authorChristian Gromm <christian.gromm@microchip.com>
Tue, 21 Nov 2017 14:04:38 +0000 (15:04 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Nov 2017 08:20:33 +0000 (09:20 +0100)
This patch renames the folder and source files of the dim2 module. It is
needed to clear the directory layout of the driver.

Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
20 files changed:
drivers/staging/most/Kconfig
drivers/staging/most/dim2/Kconfig [new file with mode: 0644]
drivers/staging/most/dim2/Makefile [new file with mode: 0644]
drivers/staging/most/dim2/dim2.c [new file with mode: 0644]
drivers/staging/most/dim2/dim2.h [new file with mode: 0644]
drivers/staging/most/dim2/errors.h [new file with mode: 0644]
drivers/staging/most/dim2/hal.c [new file with mode: 0644]
drivers/staging/most/dim2/hal.h [new file with mode: 0644]
drivers/staging/most/dim2/reg.h [new file with mode: 0644]
drivers/staging/most/dim2/sysfs.c [new file with mode: 0644]
drivers/staging/most/dim2/sysfs.h [new file with mode: 0644]
drivers/staging/most/hdm-dim2/Kconfig [deleted file]
drivers/staging/most/hdm-dim2/dim2_errors.h [deleted file]
drivers/staging/most/hdm-dim2/dim2_hal.c [deleted file]
drivers/staging/most/hdm-dim2/dim2_hal.h [deleted file]
drivers/staging/most/hdm-dim2/dim2_hdm.c [deleted file]
drivers/staging/most/hdm-dim2/dim2_hdm.h [deleted file]
drivers/staging/most/hdm-dim2/dim2_reg.h [deleted file]
drivers/staging/most/hdm-dim2/dim2_sysfs.c [deleted file]
drivers/staging/most/hdm-dim2/dim2_sysfs.h [deleted file]

index b3393a5f57061d15ab2487c508e706ee0ac51045..88a415b8d07a57e1a718b86ca9dd03801de1cffc 100644 (file)
@@ -25,7 +25,7 @@ source "drivers/staging/most/aim-sound/Kconfig"
 
 source "drivers/staging/most/aim-v4l2/Kconfig"
 
-source "drivers/staging/most/hdm-dim2/Kconfig"
+source "drivers/staging/most/dim2/Kconfig"
 
 source "drivers/staging/most/i2c/Kconfig"
 
diff --git a/drivers/staging/most/dim2/Kconfig b/drivers/staging/most/dim2/Kconfig
new file mode 100644 (file)
index 0000000..e39c4e5
--- /dev/null
@@ -0,0 +1,16 @@
+#
+# MediaLB configuration
+#
+
+config MOST_DIM2
+       tristate "DIM2"
+       depends on HAS_IOMEM
+
+       ---help---
+         Say Y here if you want to connect via MediaLB to network transceiver.
+         This device driver is platform dependent and needs an additional
+         platform driver to be installed. For more information contact
+         maintainer of this driver.
+
+         To compile this driver as a module, choose M here: the
+         module will be called most_dim2.
diff --git a/drivers/staging/most/dim2/Makefile b/drivers/staging/most/dim2/Makefile
new file mode 100644 (file)
index 0000000..66676f5
--- /dev/null
@@ -0,0 +1,4 @@
+obj-$(CONFIG_MOST_DIM2) += most_dim2.o
+
+most_dim2-objs := dim2.o hal.o sysfs.o
+ccflags-y += -Idrivers/staging/
diff --git a/drivers/staging/most/dim2/dim2.c b/drivers/staging/most/dim2/dim2.c
new file mode 100644 (file)
index 0000000..921db98
--- /dev/null
@@ -0,0 +1,912 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dim2.c - MediaLB DIM2 Hardware Dependent Module
+ *
+ * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#include "most/core.h"
+#include "hal.h"
+#include "dim2.h"
+#include "errors.h"
+#include "sysfs.h"
+
+#define DMA_CHANNELS (32 - 1)  /* channel 0 is a system channel */
+
+#define MAX_BUFFERS_PACKET      32
+#define MAX_BUFFERS_STREAMING   32
+#define MAX_BUF_SIZE_PACKET     2048
+#define MAX_BUF_SIZE_STREAMING  (8 * 1024)
+
+/* command line parameter to select clock speed */
+static char *clock_speed;
+module_param(clock_speed, charp, 0000);
+MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed");
+
+/*
+ * The parameter representing the number of frames per sub-buffer for
+ * synchronous channels.  Valid values: [0 .. 6].
+ *
+ * The values 0, 1, 2, 3, 4, 5, 6 represent corresponding number of frames per
+ * sub-buffer 1, 2, 4, 8, 16, 32, 64.
+ */
+static u8 fcnt = 4;  /* (1 << fcnt) frames per subbuffer */
+module_param(fcnt, byte, 0000);
+MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a power of 2");
+
+static DEFINE_SPINLOCK(dim_lock);
+
+static void dim2_tasklet_fn(unsigned long data);
+static DECLARE_TASKLET(dim2_tasklet, dim2_tasklet_fn, 0);
+
+/**
+ * struct hdm_channel - private structure to keep channel specific data
+ * @is_initialized: identifier to know whether the channel is initialized
+ * @ch: HAL specific channel data
+ * @pending_list: list to keep MBO's before starting transfer
+ * @started_list: list to keep MBO's after starting transfer
+ * @direction: channel direction (TX or RX)
+ * @data_type: channel data type
+ */
+struct hdm_channel {
+       char name[sizeof "caNNN"];
+       bool is_initialized;
+       struct dim_channel ch;
+       struct list_head pending_list;  /* before dim_enqueue_buffer() */
+       struct list_head started_list;  /* after dim_enqueue_buffer() */
+       enum most_channel_direction direction;
+       enum most_channel_data_type data_type;
+};
+
+/**
+ * struct dim2_hdm - private structure to keep interface specific data
+ * @hch: an array of channel specific data
+ * @most_iface: most interface structure
+ * @capabilities: an array of channel capability data
+ * @io_base: I/O register base address
+ * @clk_speed: user selectable (through command line parameter) clock speed
+ * @netinfo_task: thread to deliver network status
+ * @netinfo_waitq: waitq for the thread to sleep
+ * @deliver_netinfo: to identify whether network status received
+ * @mac_addrs: INIC mac address
+ * @link_state: network link state
+ * @atx_idx: index of async tx channel
+ */
+struct dim2_hdm {
+       struct hdm_channel hch[DMA_CHANNELS];
+       struct most_channel_capability capabilities[DMA_CHANNELS];
+       struct most_interface most_iface;
+       char name[16 + sizeof "dim2-"];
+       void __iomem *io_base;
+       int clk_speed;
+       struct task_struct *netinfo_task;
+       wait_queue_head_t netinfo_waitq;
+       int deliver_netinfo;
+       unsigned char mac_addrs[6];
+       unsigned char link_state;
+       int atx_idx;
+       struct medialb_bus bus;
+       void (*on_netinfo)(struct most_interface *,
+                          unsigned char, unsigned char *);
+};
+
+#define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface)
+
+/* Macro to identify a network status message */
+#define PACKET_IS_NET_INFO(p)  \
+       (((p)[1] == 0x18) && ((p)[2] == 0x05) && ((p)[3] == 0x0C) && \
+        ((p)[13] == 0x3C) && ((p)[14] == 0x00) && ((p)[15] == 0x0A))
+
+bool dim2_sysfs_get_state_cb(void)
+{
+       bool state;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dim_lock, flags);
+       state = dim_get_lock_state();
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       return state;
+}
+
+/**
+ * dimcb_io_read - callback from HAL to read an I/O register
+ * @ptr32: register address
+ */
+u32 dimcb_io_read(u32 __iomem *ptr32)
+{
+       return readl(ptr32);
+}
+
+/**
+ * dimcb_io_write - callback from HAL to write value to an I/O register
+ * @ptr32: register address
+ * @value: value to write
+ */
+void dimcb_io_write(u32 __iomem *ptr32, u32 value)
+{
+       writel(value, ptr32);
+}
+
+/**
+ * dimcb_on_error - callback from HAL to report miscommunication between
+ * HDM and HAL
+ * @error_id: Error ID
+ * @error_message: Error message. Some text in a free format
+ */
+void dimcb_on_error(u8 error_id, const char *error_message)
+{
+       pr_err("dimcb_on_error: error_id - %d, error_message - %s\n", error_id,
+              error_message);
+}
+
+/**
+ * startup_dim - initialize the dim2 interface
+ * @pdev: platform device
+ *
+ * Get the value of command line parameter "clock_speed" if given or use the
+ * default value, enable the clock and PLL, and initialize the dim2 interface.
+ */
+static int startup_dim(struct platform_device *pdev)
+{
+       struct dim2_hdm *dev = platform_get_drvdata(pdev);
+       struct dim2_platform_data *pdata = pdev->dev.platform_data;
+       u8 hal_ret;
+
+       dev->clk_speed = -1;
+
+       if (clock_speed) {
+               if (!strcmp(clock_speed, "256fs"))
+                       dev->clk_speed = CLK_256FS;
+               else if (!strcmp(clock_speed, "512fs"))
+                       dev->clk_speed = CLK_512FS;
+               else if (!strcmp(clock_speed, "1024fs"))
+                       dev->clk_speed = CLK_1024FS;
+               else if (!strcmp(clock_speed, "2048fs"))
+                       dev->clk_speed = CLK_2048FS;
+               else if (!strcmp(clock_speed, "3072fs"))
+                       dev->clk_speed = CLK_3072FS;
+               else if (!strcmp(clock_speed, "4096fs"))
+                       dev->clk_speed = CLK_4096FS;
+               else if (!strcmp(clock_speed, "6144fs"))
+                       dev->clk_speed = CLK_6144FS;
+               else if (!strcmp(clock_speed, "8192fs"))
+                       dev->clk_speed = CLK_8192FS;
+       }
+
+       if (dev->clk_speed == -1) {
+               pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n");
+               dev->clk_speed = CLK_3072FS;
+       } else {
+               pr_info("Selected clock speed: %s\n", clock_speed);
+       }
+       if (pdata && pdata->init) {
+               int ret = pdata->init(pdata, dev->io_base, dev->clk_speed);
+
+               if (ret)
+                       return ret;
+       }
+
+       pr_info("sync: num of frames per sub-buffer: %u\n", fcnt);
+       hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt);
+       if (hal_ret != DIM_NO_ERROR) {
+               pr_err("dim_startup failed: %d\n", hal_ret);
+               if (pdata && pdata->destroy)
+                       pdata->destroy(pdata);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+/**
+ * try_start_dim_transfer - try to transfer a buffer on a channel
+ * @hdm_ch: channel specific data
+ *
+ * Transfer a buffer from pending_list if the channel is ready
+ */
+static int try_start_dim_transfer(struct hdm_channel *hdm_ch)
+{
+       u16 buf_size;
+       struct list_head *head = &hdm_ch->pending_list;
+       struct mbo *mbo;
+       unsigned long flags;
+       struct dim_ch_state_t st;
+
+       BUG_ON(!hdm_ch);
+       BUG_ON(!hdm_ch->is_initialized);
+
+       spin_lock_irqsave(&dim_lock, flags);
+       if (list_empty(head)) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               return -EAGAIN;
+       }
+
+       if (!dim_get_channel_state(&hdm_ch->ch, &st)->ready) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               return -EAGAIN;
+       }
+
+       mbo = list_first_entry(head, struct mbo, list);
+       buf_size = mbo->buffer_length;
+
+       if (dim_dbr_space(&hdm_ch->ch) < buf_size) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               return -EAGAIN;
+       }
+
+       BUG_ON(mbo->bus_address == 0);
+       if (!dim_enqueue_buffer(&hdm_ch->ch, mbo->bus_address, buf_size)) {
+               list_del(head->next);
+               spin_unlock_irqrestore(&dim_lock, flags);
+               mbo->processed_length = 0;
+               mbo->status = MBO_E_INVAL;
+               mbo->complete(mbo);
+               return -EFAULT;
+       }
+
+       list_move_tail(head->next, &hdm_ch->started_list);
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       return 0;
+}
+
+/**
+ * deliver_netinfo_thread - thread to deliver network status to mostcore
+ * @data: private data
+ *
+ * Wait for network status and deliver it to mostcore once it is received
+ */
+static int deliver_netinfo_thread(void *data)
+{
+       struct dim2_hdm *dev = data;
+
+       while (!kthread_should_stop()) {
+               wait_event_interruptible(dev->netinfo_waitq,
+                                        dev->deliver_netinfo ||
+                                        kthread_should_stop());
+
+               if (dev->deliver_netinfo) {
+                       dev->deliver_netinfo--;
+                       if (dev->on_netinfo) {
+                               dev->on_netinfo(&dev->most_iface,
+                                               dev->link_state,
+                                               dev->mac_addrs);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * retrieve_netinfo - retrieve network status from received buffer
+ * @dev: private data
+ * @mbo: received MBO
+ *
+ * Parse the message in buffer and get node address, link state, MAC address.
+ * Wake up a thread to deliver this status to mostcore
+ */
+static void retrieve_netinfo(struct dim2_hdm *dev, struct mbo *mbo)
+{
+       u8 *data = mbo->virt_address;
+
+       pr_info("Node Address: 0x%03x\n", (u16)data[16] << 8 | data[17]);
+       dev->link_state = data[18];
+       pr_info("NIState: %d\n", dev->link_state);
+       memcpy(dev->mac_addrs, data + 19, 6);
+       dev->deliver_netinfo++;
+       wake_up_interruptible(&dev->netinfo_waitq);
+}
+
+/**
+ * service_done_flag - handle completed buffers
+ * @dev: private data
+ * @ch_idx: channel index
+ *
+ * Return back the completed buffers to mostcore, using completion callback
+ */
+static void service_done_flag(struct dim2_hdm *dev, int ch_idx)
+{
+       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
+       struct dim_ch_state_t st;
+       struct list_head *head;
+       struct mbo *mbo;
+       int done_buffers;
+       unsigned long flags;
+       u8 *data;
+
+       BUG_ON(!hdm_ch);
+       BUG_ON(!hdm_ch->is_initialized);
+
+       spin_lock_irqsave(&dim_lock, flags);
+
+       done_buffers = dim_get_channel_state(&hdm_ch->ch, &st)->done_buffers;
+       if (!done_buffers) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               return;
+       }
+
+       if (!dim_detach_buffers(&hdm_ch->ch, done_buffers)) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       head = &hdm_ch->started_list;
+
+       while (done_buffers) {
+               spin_lock_irqsave(&dim_lock, flags);
+               if (list_empty(head)) {
+                       spin_unlock_irqrestore(&dim_lock, flags);
+                       pr_crit("hard error: started_mbo list is empty whereas DIM2 has sent buffers\n");
+                       break;
+               }
+
+               mbo = list_first_entry(head, struct mbo, list);
+               list_del(head->next);
+               spin_unlock_irqrestore(&dim_lock, flags);
+
+               data = mbo->virt_address;
+
+               if (hdm_ch->data_type == MOST_CH_ASYNC &&
+                   hdm_ch->direction == MOST_CH_RX &&
+                   PACKET_IS_NET_INFO(data)) {
+                       retrieve_netinfo(dev, mbo);
+
+                       spin_lock_irqsave(&dim_lock, flags);
+                       list_add_tail(&mbo->list, &hdm_ch->pending_list);
+                       spin_unlock_irqrestore(&dim_lock, flags);
+               } else {
+                       if (hdm_ch->data_type == MOST_CH_CONTROL ||
+                           hdm_ch->data_type == MOST_CH_ASYNC) {
+                               u32 const data_size =
+                                       (u32)data[0] * 256 + data[1] + 2;
+
+                               mbo->processed_length =
+                                       min_t(u32, data_size,
+                                             mbo->buffer_length);
+                       } else {
+                               mbo->processed_length = mbo->buffer_length;
+                       }
+                       mbo->status = MBO_SUCCESS;
+                       mbo->complete(mbo);
+               }
+
+               done_buffers--;
+       }
+}
+
+static struct dim_channel **get_active_channels(struct dim2_hdm *dev,
+                                               struct dim_channel **buffer)
+{
+       int idx = 0;
+       int ch_idx;
+
+       for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) {
+               if (dev->hch[ch_idx].is_initialized)
+                       buffer[idx++] = &dev->hch[ch_idx].ch;
+       }
+       buffer[idx++] = NULL;
+
+       return buffer;
+}
+
+static irqreturn_t dim2_mlb_isr(int irq, void *_dev)
+{
+       struct dim2_hdm *dev = _dev;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dim_lock, flags);
+       dim_service_mlb_int_irq();
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       if (dev->atx_idx >= 0 && dev->hch[dev->atx_idx].is_initialized)
+               while (!try_start_dim_transfer(dev->hch + dev->atx_idx))
+                       continue;
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * dim2_tasklet_fn - tasklet function
+ * @data: private data
+ *
+ * Service each initialized channel, if needed
+ */
+static void dim2_tasklet_fn(unsigned long data)
+{
+       struct dim2_hdm *dev = (struct dim2_hdm *)data;
+       unsigned long flags;
+       int ch_idx;
+
+       for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) {
+               if (!dev->hch[ch_idx].is_initialized)
+                       continue;
+
+               spin_lock_irqsave(&dim_lock, flags);
+               dim_service_channel(&dev->hch[ch_idx].ch);
+               spin_unlock_irqrestore(&dim_lock, flags);
+
+               service_done_flag(dev, ch_idx);
+               while (!try_start_dim_transfer(dev->hch + ch_idx))
+                       continue;
+       }
+}
+
+/**
+ * dim2_ahb_isr - interrupt service routine
+ * @irq: irq number
+ * @_dev: private data
+ *
+ * Acknowledge the interrupt and schedule a tasklet to service channels.
+ * Return IRQ_HANDLED.
+ */
+static irqreturn_t dim2_ahb_isr(int irq, void *_dev)
+{
+       struct dim2_hdm *dev = _dev;
+       struct dim_channel *buffer[DMA_CHANNELS + 1];
+       unsigned long flags;
+
+       spin_lock_irqsave(&dim_lock, flags);
+       dim_service_ahb_int_irq(get_active_channels(dev, buffer));
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       dim2_tasklet.data = (unsigned long)dev;
+       tasklet_schedule(&dim2_tasklet);
+       return IRQ_HANDLED;
+}
+
+/**
+ * complete_all_mbos - complete MBO's in a list
+ * @head: list head
+ *
+ * Delete all the entries in list and return back MBO's to mostcore using
+ * completion call back.
+ */
+static void complete_all_mbos(struct list_head *head)
+{
+       unsigned long flags;
+       struct mbo *mbo;
+
+       for (;;) {
+               spin_lock_irqsave(&dim_lock, flags);
+               if (list_empty(head)) {
+                       spin_unlock_irqrestore(&dim_lock, flags);
+                       break;
+               }
+
+               mbo = list_first_entry(head, struct mbo, list);
+               list_del(head->next);
+               spin_unlock_irqrestore(&dim_lock, flags);
+
+               mbo->processed_length = 0;
+               mbo->status = MBO_E_CLOSE;
+               mbo->complete(mbo);
+       }
+}
+
+/**
+ * configure_channel - initialize a channel
+ * @iface: interface the channel belongs to
+ * @channel: channel to be configured
+ * @channel_config: structure that holds the configuration information
+ *
+ * Receives configuration information from mostcore and initialize
+ * the corresponding channel. Return 0 on success, negative on failure.
+ */
+static int configure_channel(struct most_interface *most_iface, int ch_idx,
+                            struct most_channel_config *ccfg)
+{
+       struct dim2_hdm *dev = iface_to_hdm(most_iface);
+       bool const is_tx = ccfg->direction == MOST_CH_TX;
+       u16 const sub_size = ccfg->subbuffer_size;
+       u16 const buf_size = ccfg->buffer_size;
+       u16 new_size;
+       unsigned long flags;
+       u8 hal_ret;
+       int const ch_addr = ch_idx * 2 + 2;
+       struct hdm_channel *const hdm_ch = dev->hch + ch_idx;
+
+       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
+
+       if (hdm_ch->is_initialized)
+               return -EPERM;
+
+       switch (ccfg->data_type) {
+       case MOST_CH_CONTROL:
+               new_size = dim_norm_ctrl_async_buffer_size(buf_size);
+               if (new_size == 0) {
+                       pr_err("%s: too small buffer size\n", hdm_ch->name);
+                       return -EINVAL;
+               }
+               ccfg->buffer_size = new_size;
+               if (new_size != buf_size)
+                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
+                               hdm_ch->name, buf_size, new_size);
+               spin_lock_irqsave(&dim_lock, flags);
+               hal_ret = dim_init_control(&hdm_ch->ch, is_tx, ch_addr,
+                                          is_tx ? new_size * 2 : new_size);
+               break;
+       case MOST_CH_ASYNC:
+               new_size = dim_norm_ctrl_async_buffer_size(buf_size);
+               if (new_size == 0) {
+                       pr_err("%s: too small buffer size\n", hdm_ch->name);
+                       return -EINVAL;
+               }
+               ccfg->buffer_size = new_size;
+               if (new_size != buf_size)
+                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
+                               hdm_ch->name, buf_size, new_size);
+               spin_lock_irqsave(&dim_lock, flags);
+               hal_ret = dim_init_async(&hdm_ch->ch, is_tx, ch_addr,
+                                        is_tx ? new_size * 2 : new_size);
+               break;
+       case MOST_CH_ISOC:
+               new_size = dim_norm_isoc_buffer_size(buf_size, sub_size);
+               if (new_size == 0) {
+                       pr_err("%s: invalid sub-buffer size or too small buffer size\n",
+                              hdm_ch->name);
+                       return -EINVAL;
+               }
+               ccfg->buffer_size = new_size;
+               if (new_size != buf_size)
+                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
+                               hdm_ch->name, buf_size, new_size);
+               spin_lock_irqsave(&dim_lock, flags);
+               hal_ret = dim_init_isoc(&hdm_ch->ch, is_tx, ch_addr, sub_size);
+               break;
+       case MOST_CH_SYNC:
+               new_size = dim_norm_sync_buffer_size(buf_size, sub_size);
+               if (new_size == 0) {
+                       pr_err("%s: invalid sub-buffer size or too small buffer size\n",
+                              hdm_ch->name);
+                       return -EINVAL;
+               }
+               ccfg->buffer_size = new_size;
+               if (new_size != buf_size)
+                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
+                               hdm_ch->name, buf_size, new_size);
+               spin_lock_irqsave(&dim_lock, flags);
+               hal_ret = dim_init_sync(&hdm_ch->ch, is_tx, ch_addr, sub_size);
+               break;
+       default:
+               pr_err("%s: configure failed, bad channel type: %d\n",
+                      hdm_ch->name, ccfg->data_type);
+               return -EINVAL;
+       }
+
+       if (hal_ret != DIM_NO_ERROR) {
+               spin_unlock_irqrestore(&dim_lock, flags);
+               pr_err("%s: configure failed (%d), type: %d, is_tx: %d\n",
+                      hdm_ch->name, hal_ret, ccfg->data_type, (int)is_tx);
+               return -ENODEV;
+       }
+
+       hdm_ch->data_type = ccfg->data_type;
+       hdm_ch->direction = ccfg->direction;
+       hdm_ch->is_initialized = true;
+
+       if (hdm_ch->data_type == MOST_CH_ASYNC &&
+           hdm_ch->direction == MOST_CH_TX &&
+           dev->atx_idx < 0)
+               dev->atx_idx = ch_idx;
+
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       return 0;
+}
+
+/**
+ * enqueue - enqueue a buffer for data transfer
+ * @iface: intended interface
+ * @channel: ID of the channel the buffer is intended for
+ * @mbo: pointer to the buffer object
+ *
+ * Push the buffer into pending_list and try to transfer one buffer from
+ * pending_list. Return 0 on success, negative on failure.
+ */
+static int enqueue(struct most_interface *most_iface, int ch_idx,
+                  struct mbo *mbo)
+{
+       struct dim2_hdm *dev = iface_to_hdm(most_iface);
+       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
+       unsigned long flags;
+
+       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
+
+       if (!hdm_ch->is_initialized)
+               return -EPERM;
+
+       if (mbo->bus_address == 0)
+               return -EFAULT;
+
+       spin_lock_irqsave(&dim_lock, flags);
+       list_add_tail(&mbo->list, &hdm_ch->pending_list);
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       (void)try_start_dim_transfer(hdm_ch);
+
+       return 0;
+}
+
+/**
+ * request_netinfo - triggers retrieving of network info
+ * @iface: pointer to the interface
+ * @channel_id: corresponding channel ID
+ *
+ * Send a command to INIC which triggers retrieving of network info by means of
+ * "Message exchange over MDP/MEP". Return 0 on success, negative on failure.
+ */
+static void request_netinfo(struct most_interface *most_iface, int ch_idx,
+                           void (*on_netinfo)(struct most_interface *,
+                                              unsigned char, unsigned char *))
+{
+       struct dim2_hdm *dev = iface_to_hdm(most_iface);
+       struct mbo *mbo;
+       u8 *data;
+
+       dev->on_netinfo = on_netinfo;
+       if (!on_netinfo)
+               return;
+
+       if (dev->atx_idx < 0) {
+               pr_err("Async Tx Not initialized\n");
+               return;
+       }
+
+       mbo = most_get_mbo(&dev->most_iface, dev->atx_idx, NULL);
+       if (!mbo)
+               return;
+
+       mbo->buffer_length = 5;
+
+       data = mbo->virt_address;
+
+       data[0] = 0x00; /* PML High byte */
+       data[1] = 0x03; /* PML Low byte */
+       data[2] = 0x02; /* PMHL */
+       data[3] = 0x08; /* FPH */
+       data[4] = 0x40; /* FMF (FIFO cmd msg - Triggers NAOverMDP) */
+
+       most_submit_mbo(mbo);
+}
+
+/**
+ * poison_channel - poison buffers of a channel
+ * @iface: pointer to the interface the channel to be poisoned belongs to
+ * @channel_id: corresponding channel ID
+ *
+ * Destroy a channel and complete all the buffers in both started_list &
+ * pending_list. Return 0 on success, negative on failure.
+ */
+static int poison_channel(struct most_interface *most_iface, int ch_idx)
+{
+       struct dim2_hdm *dev = iface_to_hdm(most_iface);
+       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
+       unsigned long flags;
+       u8 hal_ret;
+       int ret = 0;
+
+       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
+
+       if (!hdm_ch->is_initialized)
+               return -EPERM;
+
+       tasklet_disable(&dim2_tasklet);
+       spin_lock_irqsave(&dim_lock, flags);
+       hal_ret = dim_destroy_channel(&hdm_ch->ch);
+       hdm_ch->is_initialized = false;
+       if (ch_idx == dev->atx_idx)
+               dev->atx_idx = -1;
+       spin_unlock_irqrestore(&dim_lock, flags);
+       tasklet_enable(&dim2_tasklet);
+       if (hal_ret != DIM_NO_ERROR) {
+               pr_err("HAL Failed to close channel %s\n", hdm_ch->name);
+               ret = -EFAULT;
+       }
+
+       complete_all_mbos(&hdm_ch->started_list);
+       complete_all_mbos(&hdm_ch->pending_list);
+
+       return ret;
+}
+
+/*
+ * dim2_probe - dim2 probe handler
+ * @pdev: platform device structure
+ *
+ * Register the dim2 interface with mostcore and initialize it.
+ * Return 0 on success, negative on failure.
+ */
+static int dim2_probe(struct platform_device *pdev)
+{
+       struct dim2_hdm *dev;
+       struct resource *res;
+       int ret, i;
+       struct kobject *kobj;
+       int irq;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
+       if (!dev)
+               return -ENOMEM;
+
+       dev->atx_idx = -1;
+
+       platform_set_drvdata(pdev, dev);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dev->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dev->io_base))
+               return PTR_ERR(dev->io_base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0,
+                              "dim2_ahb0_int", dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request ahb0_int irq %d\n", irq);
+               return ret;
+       }
+
+       irq = platform_get_irq(pdev, 1);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0,
+                              "dim2_mlb_int", dev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request mlb_int irq %d\n", irq);
+               return ret;
+       }
+
+       init_waitqueue_head(&dev->netinfo_waitq);
+       dev->deliver_netinfo = 0;
+       dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev,
+                                       "dim2_netinfo");
+       if (IS_ERR(dev->netinfo_task))
+               return PTR_ERR(dev->netinfo_task);
+
+       for (i = 0; i < DMA_CHANNELS; i++) {
+               struct most_channel_capability *cap = dev->capabilities + i;
+               struct hdm_channel *hdm_ch = dev->hch + i;
+
+               INIT_LIST_HEAD(&hdm_ch->pending_list);
+               INIT_LIST_HEAD(&hdm_ch->started_list);
+               hdm_ch->is_initialized = false;
+               snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2);
+
+               cap->name_suffix = hdm_ch->name;
+               cap->direction = MOST_CH_RX | MOST_CH_TX;
+               cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC |
+                                MOST_CH_ISOC | MOST_CH_SYNC;
+               cap->num_buffers_packet = MAX_BUFFERS_PACKET;
+               cap->buffer_size_packet = MAX_BUF_SIZE_PACKET;
+               cap->num_buffers_streaming = MAX_BUFFERS_STREAMING;
+               cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING;
+       }
+
+       {
+               const char *fmt;
+
+               if (sizeof(res->start) == sizeof(long long))
+                       fmt = "dim2-%016llx";
+               else if (sizeof(res->start) == sizeof(long))
+                       fmt = "dim2-%016lx";
+               else
+                       fmt = "dim2-%016x";
+
+               snprintf(dev->name, sizeof(dev->name), fmt, res->start);
+       }
+
+       dev->most_iface.interface = ITYPE_MEDIALB_DIM2;
+       dev->most_iface.description = dev->name;
+       dev->most_iface.num_channels = DMA_CHANNELS;
+       dev->most_iface.channel_vector = dev->capabilities;
+       dev->most_iface.configure = configure_channel;
+       dev->most_iface.enqueue = enqueue;
+       dev->most_iface.poison_channel = poison_channel;
+       dev->most_iface.request_netinfo = request_netinfo;
+
+       kobj = most_register_interface(&dev->most_iface);
+       if (IS_ERR(kobj)) {
+               ret = PTR_ERR(kobj);
+               dev_err(&pdev->dev, "failed to register MOST interface\n");
+               goto err_stop_thread;
+       }
+
+       ret = dim2_sysfs_probe(&dev->bus, kobj);
+       if (ret)
+               goto err_unreg_iface;
+
+       ret = startup_dim(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to initialize DIM2\n");
+               goto err_destroy_bus;
+       }
+
+       return 0;
+
+err_destroy_bus:
+       dim2_sysfs_destroy(&dev->bus);
+err_unreg_iface:
+       most_deregister_interface(&dev->most_iface);
+err_stop_thread:
+       kthread_stop(dev->netinfo_task);
+
+       return ret;
+}
+
+/**
+ * dim2_remove - dim2 remove handler
+ * @pdev: platform device structure
+ *
+ * Unregister the interface from mostcore
+ */
+static int dim2_remove(struct platform_device *pdev)
+{
+       struct dim2_hdm *dev = platform_get_drvdata(pdev);
+       struct dim2_platform_data *pdata = pdev->dev.platform_data;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dim_lock, flags);
+       dim_shutdown();
+       spin_unlock_irqrestore(&dim_lock, flags);
+
+       if (pdata && pdata->destroy)
+               pdata->destroy(pdata);
+
+       dim2_sysfs_destroy(&dev->bus);
+       most_deregister_interface(&dev->most_iface);
+       kthread_stop(dev->netinfo_task);
+
+       /*
+        * break link to local platform_device_id struct
+        * to prevent crash by unload platform device module
+        */
+       pdev->id_entry = NULL;
+
+       return 0;
+}
+
+static const struct platform_device_id dim2_id[] = {
+       { "medialb_dim2" },
+       { }, /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(platform, dim2_id);
+
+static struct platform_driver dim2_driver = {
+       .probe = dim2_probe,
+       .remove = dim2_remove,
+       .id_table = dim2_id,
+       .driver = {
+               .name = "hdm_dim2",
+       },
+};
+
+module_platform_driver(dim2_driver);
+
+MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>");
+MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
+MODULE_DESCRIPTION("MediaLB DIM2 Hardware Dependent Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/most/dim2/dim2.h b/drivers/staging/most/dim2/dim2.h
new file mode 100644 (file)
index 0000000..6a9fc51
--- /dev/null
@@ -0,0 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * dim2.h - MediaLB DIM2 HDM Header
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+#ifndef DIM2_HDM_H
+#define        DIM2_HDM_H
+
+struct device;
+
+/* platform dependent data for dim2 interface */
+struct dim2_platform_data {
+       int (*init)(struct dim2_platform_data *pd, void __iomem *io_base,
+                   int clk_speed);
+       void (*destroy)(struct dim2_platform_data *pd);
+       void *priv;
+};
+
+#endif /* DIM2_HDM_H */
diff --git a/drivers/staging/most/dim2/errors.h b/drivers/staging/most/dim2/errors.h
new file mode 100644 (file)
index 0000000..3487510
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * errors.h - Definitions of errors for DIM2 HAL API
+ * (MediaLB, Device Interface Macro IP, OS62420)
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+#ifndef _MOST_DIM_ERRORS_H
+#define _MOST_DIM_ERRORS_H
+
+/**
+ * MOST DIM errors.
+ */
+enum dim_errors_t {
+       /** Not an error */
+       DIM_NO_ERROR = 0,
+
+       /** Bad base address for DIM2 IP */
+       DIM_INIT_ERR_DIM_ADDR = 0x10,
+
+       /**< Bad MediaLB clock */
+       DIM_INIT_ERR_MLB_CLOCK,
+
+       /** Bad channel address */
+       DIM_INIT_ERR_CHANNEL_ADDRESS,
+
+       /** Out of DBR memory */
+       DIM_INIT_ERR_OUT_OF_MEMORY,
+
+       /** DIM API is called while DIM is not initialized successfully */
+       DIM_ERR_DRIVER_NOT_INITIALIZED = 0x20,
+
+       /**
+        * Configuration does not respect hardware limitations
+        * for isochronous or synchronous channels
+        */
+       DIM_ERR_BAD_CONFIG,
+
+       /**
+        * Buffer size does not respect hardware limitations
+        * for isochronous or synchronous channels
+        */
+       DIM_ERR_BAD_BUFFER_SIZE,
+
+       DIM_ERR_UNDERFLOW,
+
+       DIM_ERR_OVERFLOW,
+};
+
+#endif /* _MOST_DIM_ERRORS_H */
diff --git a/drivers/staging/most/dim2/hal.c b/drivers/staging/most/dim2/hal.c
new file mode 100644 (file)
index 0000000..17c04e1
--- /dev/null
@@ -0,0 +1,979 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hal.c - DIM2 HAL implementation
+ * (MediaLB, Device Interface Macro IP, OS62420)
+ *
+ * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
+
+#include "hal.h"
+#include "errors.h"
+#include "reg.h"
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+
+/*
+ * Size factor for isochronous DBR buffer.
+ * Minimal value is 3.
+ */
+#define ISOC_DBR_FACTOR 3u
+
+/*
+ * Number of 32-bit units for DBR map.
+ *
+ * 1: block size is 512, max allocation is 16K
+ * 2: block size is 256, max allocation is 8K
+ * 4: block size is 128, max allocation is 4K
+ * 8: block size is 64, max allocation is 2K
+ *
+ * Min allocated space is block size.
+ * Max possible allocated space is 32 blocks.
+ */
+#define DBR_MAP_SIZE 2
+
+/* -------------------------------------------------------------------------- */
+/* not configurable area */
+
+#define CDT 0x00
+#define ADT 0x40
+#define MLB_CAT 0x80
+#define AHB_CAT 0x88
+
+#define DBR_SIZE  (16 * 1024) /* specified by IP */
+#define DBR_BLOCK_SIZE  (DBR_SIZE / 32 / DBR_MAP_SIZE)
+
+#define ROUND_UP_TO(x, d)  (DIV_ROUND_UP(x, (d)) * (d))
+
+/* -------------------------------------------------------------------------- */
+/* generic helper functions and macros */
+
+static inline u32 bit_mask(u8 position)
+{
+       return (u32)1 << position;
+}
+
+static inline bool dim_on_error(u8 error_id, const char *error_message)
+{
+       dimcb_on_error(error_id, error_message);
+       return false;
+}
+
+/* -------------------------------------------------------------------------- */
+/* types and local variables */
+
+struct async_tx_dbr {
+       u8 ch_addr;
+       u16 rpc;
+       u16 wpc;
+       u16 rest_size;
+       u16 sz_queue[CDT0_RPC_MASK + 1];
+};
+
+struct lld_global_vars_t {
+       bool dim_is_initialized;
+       bool mcm_is_initialized;
+       struct dim2_regs __iomem *dim2; /* DIM2 core base address */
+       struct async_tx_dbr atx_dbr;
+       u32 fcnt;
+       u32 dbr_map[DBR_MAP_SIZE];
+};
+
+static struct lld_global_vars_t g = { false };
+
+/* -------------------------------------------------------------------------- */
+
+static int dbr_get_mask_size(u16 size)
+{
+       int i;
+
+       for (i = 0; i < 6; i++)
+               if (size <= (DBR_BLOCK_SIZE << i))
+                       return 1 << i;
+       return 0;
+}
+
+/**
+ * Allocates DBR memory.
+ * @param size Allocating memory size.
+ * @return Offset in DBR memory by success or DBR_SIZE if out of memory.
+ */
+static int alloc_dbr(u16 size)
+{
+       int mask_size;
+       int i, block_idx = 0;
+
+       if (size <= 0)
+               return DBR_SIZE; /* out of memory */
+
+       mask_size = dbr_get_mask_size(size);
+       if (mask_size == 0)
+               return DBR_SIZE; /* out of memory */
+
+       for (i = 0; i < DBR_MAP_SIZE; i++) {
+               u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
+               u32 mask = ~((~(u32)0) << blocks);
+
+               do {
+                       if ((g.dbr_map[i] & mask) == 0) {
+                               g.dbr_map[i] |= mask;
+                               return block_idx * DBR_BLOCK_SIZE;
+                       }
+                       block_idx += mask_size;
+                       /* do shift left with 2 steps in case mask_size == 32 */
+                       mask <<= mask_size - 1;
+               } while ((mask <<= 1) != 0);
+       }
+
+       return DBR_SIZE; /* out of memory */
+}
+
+static void free_dbr(int offs, int size)
+{
+       int block_idx = offs / DBR_BLOCK_SIZE;
+       u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
+       u32 mask = ~((~(u32)0) << blocks);
+
+       mask <<= block_idx % 32;
+       g.dbr_map[block_idx / 32] &= ~mask;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void dim2_transfer_madr(u32 val)
+{
+       dimcb_io_write(&g.dim2->MADR, val);
+
+       /* wait for transfer completion */
+       while ((dimcb_io_read(&g.dim2->MCTL) & 1) != 1)
+               continue;
+
+       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
+}
+
+static void dim2_clear_dbr(u16 addr, u16 size)
+{
+       enum { MADR_TB_BIT = 30, MADR_WNR_BIT = 31 };
+
+       u16 const end_addr = addr + size;
+       u32 const cmd = bit_mask(MADR_WNR_BIT) | bit_mask(MADR_TB_BIT);
+
+       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
+       dimcb_io_write(&g.dim2->MDAT0, 0);
+
+       for (; addr < end_addr; addr++)
+               dim2_transfer_madr(cmd | addr);
+}
+
+static u32 dim2_read_ctr(u32 ctr_addr, u16 mdat_idx)
+{
+       dim2_transfer_madr(ctr_addr);
+
+       return dimcb_io_read((&g.dim2->MDAT0) + mdat_idx);
+}
+
+static void dim2_write_ctr_mask(u32 ctr_addr, const u32 *mask, const u32 *value)
+{
+       enum { MADR_WNR_BIT = 31 };
+
+       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
+
+       if (mask[0] != 0)
+               dimcb_io_write(&g.dim2->MDAT0, value[0]);
+       if (mask[1] != 0)
+               dimcb_io_write(&g.dim2->MDAT1, value[1]);
+       if (mask[2] != 0)
+               dimcb_io_write(&g.dim2->MDAT2, value[2]);
+       if (mask[3] != 0)
+               dimcb_io_write(&g.dim2->MDAT3, value[3]);
+
+       dimcb_io_write(&g.dim2->MDWE0, mask[0]);
+       dimcb_io_write(&g.dim2->MDWE1, mask[1]);
+       dimcb_io_write(&g.dim2->MDWE2, mask[2]);
+       dimcb_io_write(&g.dim2->MDWE3, mask[3]);
+
+       dim2_transfer_madr(bit_mask(MADR_WNR_BIT) | ctr_addr);
+}
+
+static inline void dim2_write_ctr(u32 ctr_addr, const u32 *value)
+{
+       u32 const mask[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+
+       dim2_write_ctr_mask(ctr_addr, mask, value);
+}
+
+static inline void dim2_clear_ctr(u32 ctr_addr)
+{
+       u32 const value[4] = { 0, 0, 0, 0 };
+
+       dim2_write_ctr(ctr_addr, value);
+}
+
+static void dim2_configure_cat(u8 cat_base, u8 ch_addr, u8 ch_type,
+                              bool read_not_write)
+{
+       bool isoc_fce = ch_type == CAT_CT_VAL_ISOC;
+       bool sync_mfe = ch_type == CAT_CT_VAL_SYNC;
+       u16 const cat =
+               (read_not_write << CAT_RNW_BIT) |
+               (ch_type << CAT_CT_SHIFT) |
+               (ch_addr << CAT_CL_SHIFT) |
+               (isoc_fce << CAT_FCE_BIT) |
+               (sync_mfe << CAT_MFE_BIT) |
+               (false << CAT_MT_BIT) |
+               (true << CAT_CE_BIT);
+       u8 const ctr_addr = cat_base + ch_addr / 8;
+       u8 const idx = (ch_addr % 8) / 2;
+       u8 const shift = (ch_addr % 2) * 16;
+       u32 mask[4] = { 0, 0, 0, 0 };
+       u32 value[4] = { 0, 0, 0, 0 };
+
+       mask[idx] = (u32)0xFFFF << shift;
+       value[idx] = cat << shift;
+       dim2_write_ctr_mask(ctr_addr, mask, value);
+}
+
+static void dim2_clear_cat(u8 cat_base, u8 ch_addr)
+{
+       u8 const ctr_addr = cat_base + ch_addr / 8;
+       u8 const idx = (ch_addr % 8) / 2;
+       u8 const shift = (ch_addr % 2) * 16;
+       u32 mask[4] = { 0, 0, 0, 0 };
+       u32 value[4] = { 0, 0, 0, 0 };
+
+       mask[idx] = (u32)0xFFFF << shift;
+       dim2_write_ctr_mask(ctr_addr, mask, value);
+}
+
+static void dim2_configure_cdt(u8 ch_addr, u16 dbr_address, u16 hw_buffer_size,
+                              u16 packet_length)
+{
+       u32 cdt[4] = { 0, 0, 0, 0 };
+
+       if (packet_length)
+               cdt[1] = ((packet_length - 1) << CDT1_BS_ISOC_SHIFT);
+
+       cdt[3] =
+               ((hw_buffer_size - 1) << CDT3_BD_SHIFT) |
+               (dbr_address << CDT3_BA_SHIFT);
+       dim2_write_ctr(CDT + ch_addr, cdt);
+}
+
+static u16 dim2_rpc(u8 ch_addr)
+{
+       u32 cdt0 = dim2_read_ctr(CDT + ch_addr, 0);
+
+       return (cdt0 >> CDT0_RPC_SHIFT) & CDT0_RPC_MASK;
+}
+
+static void dim2_clear_cdt(u8 ch_addr)
+{
+       u32 cdt[4] = { 0, 0, 0, 0 };
+
+       dim2_write_ctr(CDT + ch_addr, cdt);
+}
+
+static void dim2_configure_adt(u8 ch_addr)
+{
+       u32 adt[4] = { 0, 0, 0, 0 };
+
+       adt[0] =
+               (true << ADT0_CE_BIT) |
+               (true << ADT0_LE_BIT) |
+               (0 << ADT0_PG_BIT);
+
+       dim2_write_ctr(ADT + ch_addr, adt);
+}
+
+static void dim2_clear_adt(u8 ch_addr)
+{
+       u32 adt[4] = { 0, 0, 0, 0 };
+
+       dim2_write_ctr(ADT + ch_addr, adt);
+}
+
+static void dim2_start_ctrl_async(u8 ch_addr, u8 idx, u32 buf_addr,
+                                 u16 buffer_size)
+{
+       u8 const shift = idx * 16;
+
+       u32 mask[4] = { 0, 0, 0, 0 };
+       u32 adt[4] = { 0, 0, 0, 0 };
+
+       mask[1] =
+               bit_mask(ADT1_PS_BIT + shift) |
+               bit_mask(ADT1_RDY_BIT + shift) |
+               (ADT1_CTRL_ASYNC_BD_MASK << (ADT1_BD_SHIFT + shift));
+       adt[1] =
+               (true << (ADT1_PS_BIT + shift)) |
+               (true << (ADT1_RDY_BIT + shift)) |
+               ((buffer_size - 1) << (ADT1_BD_SHIFT + shift));
+
+       mask[idx + 2] = 0xFFFFFFFF;
+       adt[idx + 2] = buf_addr;
+
+       dim2_write_ctr_mask(ADT + ch_addr, mask, adt);
+}
+
+static void dim2_start_isoc_sync(u8 ch_addr, u8 idx, u32 buf_addr,
+                                u16 buffer_size)
+{
+       u8 const shift = idx * 16;
+
+       u32 mask[4] = { 0, 0, 0, 0 };
+       u32 adt[4] = { 0, 0, 0, 0 };
+
+       mask[1] =
+               bit_mask(ADT1_RDY_BIT + shift) |
+               (ADT1_ISOC_SYNC_BD_MASK << (ADT1_BD_SHIFT + shift));
+       adt[1] =
+               (true << (ADT1_RDY_BIT + shift)) |
+               ((buffer_size - 1) << (ADT1_BD_SHIFT + shift));
+
+       mask[idx + 2] = 0xFFFFFFFF;
+       adt[idx + 2] = buf_addr;
+
+       dim2_write_ctr_mask(ADT + ch_addr, mask, adt);
+}
+
+static void dim2_clear_ctram(void)
+{
+       u32 ctr_addr;
+
+       for (ctr_addr = 0; ctr_addr < 0x90; ctr_addr++)
+               dim2_clear_ctr(ctr_addr);
+}
+
+static void dim2_configure_channel(
+       u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size,
+       u16 packet_length)
+{
+       dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length);
+       dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0);
+
+       dim2_configure_adt(ch_addr);
+       dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1);
+
+       /* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */
+       dimcb_io_write(&g.dim2->ACMR0,
+                      dimcb_io_read(&g.dim2->ACMR0) | bit_mask(ch_addr));
+}
+
+static void dim2_clear_channel(u8 ch_addr)
+{
+       /* mask interrupt for used channel, disable mlb_sys_int[0] interrupt */
+       dimcb_io_write(&g.dim2->ACMR0,
+                      dimcb_io_read(&g.dim2->ACMR0) & ~bit_mask(ch_addr));
+
+       dim2_clear_cat(AHB_CAT, ch_addr);
+       dim2_clear_adt(ch_addr);
+
+       dim2_clear_cat(MLB_CAT, ch_addr);
+       dim2_clear_cdt(ch_addr);
+
+       /* clear channel status bit */
+       dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
+}
+
+/* -------------------------------------------------------------------------- */
+/* trace async tx dbr fill state */
+
+static inline u16 norm_pc(u16 pc)
+{
+       return pc & CDT0_RPC_MASK;
+}
+
+static void dbrcnt_init(u8 ch_addr, u16 dbr_size)
+{
+       g.atx_dbr.rest_size = dbr_size;
+       g.atx_dbr.rpc = dim2_rpc(ch_addr);
+       g.atx_dbr.wpc = g.atx_dbr.rpc;
+}
+
+static void dbrcnt_enq(int buf_sz)
+{
+       g.atx_dbr.rest_size -= buf_sz;
+       g.atx_dbr.sz_queue[norm_pc(g.atx_dbr.wpc)] = buf_sz;
+       g.atx_dbr.wpc++;
+}
+
+u16 dim_dbr_space(struct dim_channel *ch)
+{
+       u16 cur_rpc;
+       struct async_tx_dbr *dbr = &g.atx_dbr;
+
+       if (ch->addr != dbr->ch_addr)
+               return 0xFFFF;
+
+       cur_rpc = dim2_rpc(ch->addr);
+
+       while (norm_pc(dbr->rpc) != cur_rpc) {
+               dbr->rest_size += dbr->sz_queue[norm_pc(dbr->rpc)];
+               dbr->rpc++;
+       }
+
+       if ((u16)(dbr->wpc - dbr->rpc) >= CDT0_RPC_MASK)
+               return 0;
+
+       return dbr->rest_size;
+}
+
+/* -------------------------------------------------------------------------- */
+/* channel state helpers */
+
+static void state_init(struct int_ch_state *state)
+{
+       state->request_counter = 0;
+       state->service_counter = 0;
+
+       state->idx1 = 0;
+       state->idx2 = 0;
+       state->level = 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* macro helper functions */
+
+static inline bool check_channel_address(u32 ch_address)
+{
+       return ch_address > 0 && (ch_address % 2) == 0 &&
+              (ch_address / 2) <= (u32)CAT_CL_MASK;
+}
+
+static inline bool check_packet_length(u32 packet_length)
+{
+       u16 const max_size = ((u16)CDT3_BD_ISOC_MASK + 1u) / ISOC_DBR_FACTOR;
+
+       if (packet_length <= 0)
+               return false; /* too small */
+
+       if (packet_length > max_size)
+               return false; /* too big */
+
+       if (packet_length - 1u > (u32)CDT1_BS_ISOC_MASK)
+               return false; /* too big */
+
+       return true;
+}
+
+static inline bool check_bytes_per_frame(u32 bytes_per_frame)
+{
+       u16 const bd_factor = g.fcnt + 2;
+       u16 const max_size = ((u16)CDT3_BD_MASK + 1u) >> bd_factor;
+
+       if (bytes_per_frame <= 0)
+               return false; /* too small */
+
+       if (bytes_per_frame > max_size)
+               return false; /* too big */
+
+       return true;
+}
+
+static inline u16 norm_ctrl_async_buffer_size(u16 buf_size)
+{
+       u16 const max_size = (u16)ADT1_CTRL_ASYNC_BD_MASK + 1u;
+
+       if (buf_size > max_size)
+               return max_size;
+
+       return buf_size;
+}
+
+static inline u16 norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
+{
+       u16 n;
+       u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u;
+
+       if (buf_size > max_size)
+               buf_size = max_size;
+
+       n = buf_size / packet_length;
+
+       if (n < 2u)
+               return 0; /* too small buffer for given packet_length */
+
+       return packet_length * n;
+}
+
+static inline u16 norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
+{
+       u16 n;
+       u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u;
+       u32 const unit = bytes_per_frame << g.fcnt;
+
+       if (buf_size > max_size)
+               buf_size = max_size;
+
+       n = buf_size / unit;
+
+       if (n < 1u)
+               return 0; /* too small buffer for given bytes_per_frame */
+
+       return unit * n;
+}
+
+static void dim2_cleanup(void)
+{
+       /* disable MediaLB */
+       dimcb_io_write(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT);
+
+       dim2_clear_ctram();
+
+       /* disable mlb_int interrupt */
+       dimcb_io_write(&g.dim2->MIEN, 0);
+
+       /* clear status for all dma channels */
+       dimcb_io_write(&g.dim2->ACSR0, 0xFFFFFFFF);
+       dimcb_io_write(&g.dim2->ACSR1, 0xFFFFFFFF);
+
+       /* mask interrupts for all channels */
+       dimcb_io_write(&g.dim2->ACMR0, 0);
+       dimcb_io_write(&g.dim2->ACMR1, 0);
+}
+
+static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
+{
+       dim2_cleanup();
+
+       /* configure and enable MediaLB */
+       dimcb_io_write(&g.dim2->MLBC0,
+                      enable_6pin << MLBC0_MLBPEN_BIT |
+                      mlb_clock << MLBC0_MLBCLK_SHIFT |
+                      g.fcnt << MLBC0_FCNT_SHIFT |
+                      true << MLBC0_MLBEN_BIT);
+
+       /* activate all HBI channels */
+       dimcb_io_write(&g.dim2->HCMR0, 0xFFFFFFFF);
+       dimcb_io_write(&g.dim2->HCMR1, 0xFFFFFFFF);
+
+       /* enable HBI */
+       dimcb_io_write(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT));
+
+       /* configure DMA */
+       dimcb_io_write(&g.dim2->ACTL,
+                      ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
+                      true << ACTL_SCE_BIT);
+}
+
+static bool dim2_is_mlb_locked(void)
+{
+       u32 const mask0 = bit_mask(MLBC0_MLBLK_BIT);
+       u32 const mask1 = bit_mask(MLBC1_CLKMERR_BIT) |
+                         bit_mask(MLBC1_LOCKERR_BIT);
+       u32 const c1 = dimcb_io_read(&g.dim2->MLBC1);
+       u32 const nda_mask = (u32)MLBC1_NDA_MASK << MLBC1_NDA_SHIFT;
+
+       dimcb_io_write(&g.dim2->MLBC1, c1 & nda_mask);
+       return (dimcb_io_read(&g.dim2->MLBC1) & mask1) == 0 &&
+              (dimcb_io_read(&g.dim2->MLBC0) & mask0) != 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* channel help routines */
+
+static inline bool service_channel(u8 ch_addr, u8 idx)
+{
+       u8 const shift = idx * 16;
+       u32 const adt1 = dim2_read_ctr(ADT + ch_addr, 1);
+       u32 mask[4] = { 0, 0, 0, 0 };
+       u32 adt_w[4] = { 0, 0, 0, 0 };
+
+       if (((adt1 >> (ADT1_DNE_BIT + shift)) & 1) == 0)
+               return false;
+
+       mask[1] =
+               bit_mask(ADT1_DNE_BIT + shift) |
+               bit_mask(ADT1_ERR_BIT + shift) |
+               bit_mask(ADT1_RDY_BIT + shift);
+       dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w);
+
+       /* clear channel status bit */
+       dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
+
+       return true;
+}
+
+/* -------------------------------------------------------------------------- */
+/* channel init routines */
+
+static void isoc_init(struct dim_channel *ch, u8 ch_addr, u16 packet_length)
+{
+       state_init(&ch->state);
+
+       ch->addr = ch_addr;
+
+       ch->packet_length = packet_length;
+       ch->bytes_per_frame = 0;
+       ch->done_sw_buffers_number = 0;
+}
+
+static void sync_init(struct dim_channel *ch, u8 ch_addr, u16 bytes_per_frame)
+{
+       state_init(&ch->state);
+
+       ch->addr = ch_addr;
+
+       ch->packet_length = 0;
+       ch->bytes_per_frame = bytes_per_frame;
+       ch->done_sw_buffers_number = 0;
+}
+
+static void channel_init(struct dim_channel *ch, u8 ch_addr)
+{
+       state_init(&ch->state);
+
+       ch->addr = ch_addr;
+
+       ch->packet_length = 0;
+       ch->bytes_per_frame = 0;
+       ch->done_sw_buffers_number = 0;
+}
+
+/* returns true if channel interrupt state is cleared */
+static bool channel_service_interrupt(struct dim_channel *ch)
+{
+       struct int_ch_state *const state = &ch->state;
+
+       if (!service_channel(ch->addr, state->idx2))
+               return false;
+
+       state->idx2 ^= 1;
+       state->request_counter++;
+       return true;
+}
+
+static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size)
+{
+       struct int_ch_state *const state = &ch->state;
+
+       if (buf_size <= 0)
+               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, "Bad buffer size");
+
+       if (ch->packet_length == 0 && ch->bytes_per_frame == 0 &&
+           buf_size != norm_ctrl_async_buffer_size(buf_size))
+               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
+                                   "Bad control/async buffer size");
+
+       if (ch->packet_length &&
+           buf_size != norm_isoc_buffer_size(buf_size, ch->packet_length))
+               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
+                                   "Bad isochronous buffer size");
+
+       if (ch->bytes_per_frame &&
+           buf_size != norm_sync_buffer_size(buf_size, ch->bytes_per_frame))
+               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
+                                   "Bad synchronous buffer size");
+
+       if (state->level >= 2u)
+               return dim_on_error(DIM_ERR_OVERFLOW, "Channel overflow");
+
+       ++state->level;
+
+       if (ch->addr == g.atx_dbr.ch_addr)
+               dbrcnt_enq(buf_size);
+
+       if (ch->packet_length || ch->bytes_per_frame)
+               dim2_start_isoc_sync(ch->addr, state->idx1, buf_addr, buf_size);
+       else
+               dim2_start_ctrl_async(ch->addr, state->idx1, buf_addr,
+                                     buf_size);
+       state->idx1 ^= 1;
+
+       return true;
+}
+
+static u8 channel_service(struct dim_channel *ch)
+{
+       struct int_ch_state *const state = &ch->state;
+
+       if (state->service_counter != state->request_counter) {
+               state->service_counter++;
+               if (state->level == 0)
+                       return DIM_ERR_UNDERFLOW;
+
+               --state->level;
+               ch->done_sw_buffers_number++;
+       }
+
+       return DIM_NO_ERROR;
+}
+
+static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number)
+{
+       if (buffers_number > ch->done_sw_buffers_number)
+               return dim_on_error(DIM_ERR_UNDERFLOW, "Channel underflow");
+
+       ch->done_sw_buffers_number -= buffers_number;
+       return true;
+}
+
+/* -------------------------------------------------------------------------- */
+/* API */
+
+u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock,
+              u32 fcnt)
+{
+       g.dim_is_initialized = false;
+
+       if (!dim_base_address)
+               return DIM_INIT_ERR_DIM_ADDR;
+
+       /* MediaLB clock: 0 - 256 fs, 1 - 512 fs, 2 - 1024 fs, 3 - 2048 fs */
+       /* MediaLB clock: 4 - 3072 fs, 5 - 4096 fs, 6 - 6144 fs, 7 - 8192 fs */
+       if (mlb_clock >= 8)
+               return DIM_INIT_ERR_MLB_CLOCK;
+
+       if (fcnt > MLBC0_FCNT_MAX_VAL)
+               return DIM_INIT_ERR_MLB_CLOCK;
+
+       g.dim2 = dim_base_address;
+       g.fcnt = fcnt;
+       g.dbr_map[0] = 0;
+       g.dbr_map[1] = 0;
+
+       dim2_initialize(mlb_clock >= 3, mlb_clock);
+
+       g.dim_is_initialized = true;
+
+       return DIM_NO_ERROR;
+}
+
+void dim_shutdown(void)
+{
+       g.dim_is_initialized = false;
+       dim2_cleanup();
+}
+
+bool dim_get_lock_state(void)
+{
+       return dim2_is_mlb_locked();
+}
+
+static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
+                         u16 ch_address, u16 hw_buffer_size)
+{
+       if (!g.dim_is_initialized || !ch)
+               return DIM_ERR_DRIVER_NOT_INITIALIZED;
+
+       if (!check_channel_address(ch_address))
+               return DIM_INIT_ERR_CHANNEL_ADDRESS;
+
+       ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE);
+       ch->dbr_addr = alloc_dbr(ch->dbr_size);
+       if (ch->dbr_addr >= DBR_SIZE)
+               return DIM_INIT_ERR_OUT_OF_MEMORY;
+
+       channel_init(ch, ch_address / 2);
+
+       dim2_configure_channel(ch->addr, type, is_tx,
+                              ch->dbr_addr, ch->dbr_size, 0);
+
+       return DIM_NO_ERROR;
+}
+
+void dim_service_mlb_int_irq(void)
+{
+       dimcb_io_write(&g.dim2->MS0, 0);
+       dimcb_io_write(&g.dim2->MS1, 0);
+}
+
+u16 dim_norm_ctrl_async_buffer_size(u16 buf_size)
+{
+       return norm_ctrl_async_buffer_size(buf_size);
+}
+
+/**
+ * Retrieves maximal possible correct buffer size for isochronous data type
+ * conform to given packet length and not bigger than given buffer size.
+ *
+ * Returns non-zero correct buffer size or zero by error.
+ */
+u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
+{
+       if (!check_packet_length(packet_length))
+               return 0;
+
+       return norm_isoc_buffer_size(buf_size, packet_length);
+}
+
+/**
+ * Retrieves maximal possible correct buffer size for synchronous data type
+ * conform to given bytes per frame and not bigger than given buffer size.
+ *
+ * Returns non-zero correct buffer size or zero by error.
+ */
+u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
+{
+       if (!check_bytes_per_frame(bytes_per_frame))
+               return 0;
+
+       return norm_sync_buffer_size(buf_size, bytes_per_frame);
+}
+
+u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                   u16 max_buffer_size)
+{
+       return init_ctrl_async(ch, CAT_CT_VAL_CONTROL, is_tx, ch_address,
+                              max_buffer_size);
+}
+
+u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                 u16 max_buffer_size)
+{
+       u8 ret = init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address,
+                                max_buffer_size);
+
+       if (is_tx && !g.atx_dbr.ch_addr) {
+               g.atx_dbr.ch_addr = ch->addr;
+               dbrcnt_init(ch->addr, ch->dbr_size);
+               dimcb_io_write(&g.dim2->MIEN, bit_mask(20));
+       }
+
+       return ret;
+}
+
+u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                u16 packet_length)
+{
+       if (!g.dim_is_initialized || !ch)
+               return DIM_ERR_DRIVER_NOT_INITIALIZED;
+
+       if (!check_channel_address(ch_address))
+               return DIM_INIT_ERR_CHANNEL_ADDRESS;
+
+       if (!check_packet_length(packet_length))
+               return DIM_ERR_BAD_CONFIG;
+
+       ch->dbr_size = packet_length * ISOC_DBR_FACTOR;
+       ch->dbr_addr = alloc_dbr(ch->dbr_size);
+       if (ch->dbr_addr >= DBR_SIZE)
+               return DIM_INIT_ERR_OUT_OF_MEMORY;
+
+       isoc_init(ch, ch_address / 2, packet_length);
+
+       dim2_configure_channel(ch->addr, CAT_CT_VAL_ISOC, is_tx, ch->dbr_addr,
+                              ch->dbr_size, packet_length);
+
+       return DIM_NO_ERROR;
+}
+
+u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                u16 bytes_per_frame)
+{
+       u16 bd_factor = g.fcnt + 2;
+
+       if (!g.dim_is_initialized || !ch)
+               return DIM_ERR_DRIVER_NOT_INITIALIZED;
+
+       if (!check_channel_address(ch_address))
+               return DIM_INIT_ERR_CHANNEL_ADDRESS;
+
+       if (!check_bytes_per_frame(bytes_per_frame))
+               return DIM_ERR_BAD_CONFIG;
+
+       ch->dbr_size = bytes_per_frame << bd_factor;
+       ch->dbr_addr = alloc_dbr(ch->dbr_size);
+       if (ch->dbr_addr >= DBR_SIZE)
+               return DIM_INIT_ERR_OUT_OF_MEMORY;
+
+       sync_init(ch, ch_address / 2, bytes_per_frame);
+
+       dim2_clear_dbr(ch->dbr_addr, ch->dbr_size);
+       dim2_configure_channel(ch->addr, CAT_CT_VAL_SYNC, is_tx,
+                              ch->dbr_addr, ch->dbr_size, 0);
+
+       return DIM_NO_ERROR;
+}
+
+u8 dim_destroy_channel(struct dim_channel *ch)
+{
+       if (!g.dim_is_initialized || !ch)
+               return DIM_ERR_DRIVER_NOT_INITIALIZED;
+
+       if (ch->addr == g.atx_dbr.ch_addr) {
+               dimcb_io_write(&g.dim2->MIEN, 0);
+               g.atx_dbr.ch_addr = 0;
+       }
+
+       dim2_clear_channel(ch->addr);
+       if (ch->dbr_addr < DBR_SIZE)
+               free_dbr(ch->dbr_addr, ch->dbr_size);
+       ch->dbr_addr = DBR_SIZE;
+
+       return DIM_NO_ERROR;
+}
+
+void dim_service_ahb_int_irq(struct dim_channel *const *channels)
+{
+       bool state_changed;
+
+       if (!g.dim_is_initialized) {
+               dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
+                            "DIM is not initialized");
+               return;
+       }
+
+       if (!channels) {
+               dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channels");
+               return;
+       }
+
+       /*
+        * Use while-loop and a flag to make sure the age is changed back at
+        * least once, otherwise the interrupt may never come if CPU generates
+        * interrupt on changing age.
+        * This cycle runs not more than number of channels, because
+        * channel_service_interrupt() routine doesn't start the channel again.
+        */
+       do {
+               struct dim_channel *const *ch = channels;
+
+               state_changed = false;
+
+               while (*ch) {
+                       state_changed |= channel_service_interrupt(*ch);
+                       ++ch;
+               }
+       } while (state_changed);
+}
+
+u8 dim_service_channel(struct dim_channel *ch)
+{
+       if (!g.dim_is_initialized || !ch)
+               return DIM_ERR_DRIVER_NOT_INITIALIZED;
+
+       return channel_service(ch);
+}
+
+struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
+                                            struct dim_ch_state_t *state_ptr)
+{
+       if (!ch || !state_ptr)
+               return NULL;
+
+       state_ptr->ready = ch->state.level < 2;
+       state_ptr->done_buffers = ch->done_sw_buffers_number;
+
+       return state_ptr;
+}
+
+bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
+                       u16 buffer_size)
+{
+       if (!ch)
+               return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
+                                   "Bad channel");
+
+       return channel_start(ch, buffer_addr, buffer_size);
+}
+
+bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number)
+{
+       if (!ch)
+               return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
+                                   "Bad channel");
+
+       return channel_detach_buffers(ch, buffers_number);
+}
diff --git a/drivers/staging/most/dim2/hal.h b/drivers/staging/most/dim2/hal.h
new file mode 100644 (file)
index 0000000..e04a535
--- /dev/null
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * hal.h - DIM2 HAL interface
+ * (MediaLB, Device Interface Macro IP, OS62420)
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+#ifndef _DIM2_HAL_H
+#define _DIM2_HAL_H
+
+#include <linux/types.h>
+#include "reg.h"
+
+/*
+ * The values below are specified in the hardware specification.
+ * So, they should not be changed until the hardware specification changes.
+ */
+enum mlb_clk_speed {
+       CLK_256FS = 0,
+       CLK_512FS = 1,
+       CLK_1024FS = 2,
+       CLK_2048FS = 3,
+       CLK_3072FS = 4,
+       CLK_4096FS = 5,
+       CLK_6144FS = 6,
+       CLK_8192FS = 7,
+};
+
+struct dim_ch_state_t {
+       bool ready; /* Shows readiness to enqueue next buffer */
+       u16 done_buffers; /* Number of completed buffers */
+};
+
+struct int_ch_state {
+       /* changed only in interrupt context */
+       volatile int request_counter;
+
+       /* changed only in task context */
+       volatile int service_counter;
+
+       u8 idx1;
+       u8 idx2;
+       u8 level; /* [0..2], buffering level */
+};
+
+struct dim_channel {
+       struct int_ch_state state;
+       u8 addr;
+       u16 dbr_addr;
+       u16 dbr_size;
+       u16 packet_length; /*< Isochronous packet length in bytes. */
+       u16 bytes_per_frame; /*< Synchronous bytes per frame. */
+       u16 done_sw_buffers_number; /*< Done software buffers number. */
+};
+
+u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock,
+              u32 fcnt);
+
+void dim_shutdown(void);
+
+bool dim_get_lock_state(void);
+
+u16 dim_norm_ctrl_async_buffer_size(u16 buf_size);
+
+u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length);
+
+u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame);
+
+u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                   u16 max_buffer_size);
+
+u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                 u16 max_buffer_size);
+
+u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                u16 packet_length);
+
+u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
+                u16 bytes_per_frame);
+
+u8 dim_destroy_channel(struct dim_channel *ch);
+
+void dim_service_mlb_int_irq(void);
+
+void dim_service_ahb_int_irq(struct dim_channel *const *channels);
+
+u8 dim_service_channel(struct dim_channel *ch);
+
+struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
+                                            struct dim_ch_state_t *state_ptr);
+
+u16 dim_dbr_space(struct dim_channel *ch);
+
+bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
+                       u16 buffer_size);
+
+bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number);
+
+u32 dimcb_io_read(u32 __iomem *ptr32);
+
+void dimcb_io_write(u32 __iomem *ptr32, u32 value);
+
+void dimcb_on_error(u8 error_id, const char *error_message);
+
+#endif /* _DIM2_HAL_H */
diff --git a/drivers/staging/most/dim2/reg.h b/drivers/staging/most/dim2/reg.h
new file mode 100644 (file)
index 0000000..69cbf78
--- /dev/null
@@ -0,0 +1,157 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * reg.h - Definitions for registers of DIM2
+ * (MediaLB, Device Interface Macro IP, OS62420)
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+#ifndef DIM2_OS62420_H
+#define        DIM2_OS62420_H
+
+#include <linux/types.h>
+
+struct dim2_regs {
+       /* 0x00 */ u32 MLBC0;
+       /* 0x01 */ u32 rsvd0[1];
+       /* 0x02 */ u32 MLBPC0;
+       /* 0x03 */ u32 MS0;
+       /* 0x04 */ u32 rsvd1[1];
+       /* 0x05 */ u32 MS1;
+       /* 0x06 */ u32 rsvd2[2];
+       /* 0x08 */ u32 MSS;
+       /* 0x09 */ u32 MSD;
+       /* 0x0A */ u32 rsvd3[1];
+       /* 0x0B */ u32 MIEN;
+       /* 0x0C */ u32 rsvd4[1];
+       /* 0x0D */ u32 MLBPC2;
+       /* 0x0E */ u32 MLBPC1;
+       /* 0x0F */ u32 MLBC1;
+       /* 0x10 */ u32 rsvd5[0x10];
+       /* 0x20 */ u32 HCTL;
+       /* 0x21 */ u32 rsvd6[1];
+       /* 0x22 */ u32 HCMR0;
+       /* 0x23 */ u32 HCMR1;
+       /* 0x24 */ u32 HCER0;
+       /* 0x25 */ u32 HCER1;
+       /* 0x26 */ u32 HCBR0;
+       /* 0x27 */ u32 HCBR1;
+       /* 0x28 */ u32 rsvd7[8];
+       /* 0x30 */ u32 MDAT0;
+       /* 0x31 */ u32 MDAT1;
+       /* 0x32 */ u32 MDAT2;
+       /* 0x33 */ u32 MDAT3;
+       /* 0x34 */ u32 MDWE0;
+       /* 0x35 */ u32 MDWE1;
+       /* 0x36 */ u32 MDWE2;
+       /* 0x37 */ u32 MDWE3;
+       /* 0x38 */ u32 MCTL;
+       /* 0x39 */ u32 MADR;
+       /* 0x3A */ u32 rsvd8[0xB6];
+       /* 0xF0 */ u32 ACTL;
+       /* 0xF1 */ u32 rsvd9[3];
+       /* 0xF4 */ u32 ACSR0;
+       /* 0xF5 */ u32 ACSR1;
+       /* 0xF6 */ u32 ACMR0;
+       /* 0xF7 */ u32 ACMR1;
+};
+
+#define DIM2_MASK(n)  (~((~(u32)0) << (n)))
+
+enum {
+       MLBC0_MLBLK_BIT = 7,
+
+       MLBC0_MLBPEN_BIT = 5,
+
+       MLBC0_MLBCLK_SHIFT = 2,
+       MLBC0_MLBCLK_VAL_256FS = 0,
+       MLBC0_MLBCLK_VAL_512FS = 1,
+       MLBC0_MLBCLK_VAL_1024FS = 2,
+       MLBC0_MLBCLK_VAL_2048FS = 3,
+
+       MLBC0_FCNT_SHIFT = 15,
+       MLBC0_FCNT_MASK = 7,
+       MLBC0_FCNT_MAX_VAL = 6,
+
+       MLBC0_MLBEN_BIT = 0,
+
+       MIEN_CTX_BREAK_BIT = 29,
+       MIEN_CTX_PE_BIT = 28,
+       MIEN_CTX_DONE_BIT = 27,
+
+       MIEN_CRX_BREAK_BIT = 26,
+       MIEN_CRX_PE_BIT = 25,
+       MIEN_CRX_DONE_BIT = 24,
+
+       MIEN_ATX_BREAK_BIT = 22,
+       MIEN_ATX_PE_BIT = 21,
+       MIEN_ATX_DONE_BIT = 20,
+
+       MIEN_ARX_BREAK_BIT = 19,
+       MIEN_ARX_PE_BIT = 18,
+       MIEN_ARX_DONE_BIT = 17,
+
+       MIEN_SYNC_PE_BIT = 16,
+
+       MIEN_ISOC_BUFO_BIT = 1,
+       MIEN_ISOC_PE_BIT = 0,
+
+       MLBC1_NDA_SHIFT = 8,
+       MLBC1_NDA_MASK = 0xFF,
+
+       MLBC1_CLKMERR_BIT = 7,
+       MLBC1_LOCKERR_BIT = 6,
+
+       ACTL_DMA_MODE_BIT = 2,
+       ACTL_DMA_MODE_VAL_DMA_MODE_0 = 0,
+       ACTL_DMA_MODE_VAL_DMA_MODE_1 = 1,
+       ACTL_SCE_BIT = 0,
+
+       HCTL_EN_BIT = 15
+};
+
+enum {
+       CDT0_RPC_SHIFT = 16 + 11,
+       CDT0_RPC_MASK = DIM2_MASK(5),
+
+       CDT1_BS_ISOC_SHIFT = 0,
+       CDT1_BS_ISOC_MASK = DIM2_MASK(9),
+
+       CDT3_BD_SHIFT = 0,
+       CDT3_BD_MASK = DIM2_MASK(12),
+       CDT3_BD_ISOC_MASK = DIM2_MASK(13),
+       CDT3_BA_SHIFT = 16,
+
+       ADT0_CE_BIT = 15,
+       ADT0_LE_BIT = 14,
+       ADT0_PG_BIT = 13,
+
+       ADT1_RDY_BIT = 15,
+       ADT1_DNE_BIT = 14,
+       ADT1_ERR_BIT = 13,
+       ADT1_PS_BIT = 12,
+       ADT1_MEP_BIT = 11,
+       ADT1_BD_SHIFT = 0,
+       ADT1_CTRL_ASYNC_BD_MASK = DIM2_MASK(11),
+       ADT1_ISOC_SYNC_BD_MASK = DIM2_MASK(13),
+
+       CAT_FCE_BIT = 14,
+       CAT_MFE_BIT = 14,
+
+       CAT_MT_BIT = 13,
+
+       CAT_RNW_BIT = 12,
+
+       CAT_CE_BIT = 11,
+
+       CAT_CT_SHIFT = 8,
+       CAT_CT_VAL_SYNC = 0,
+       CAT_CT_VAL_CONTROL = 1,
+       CAT_CT_VAL_ASYNC = 2,
+       CAT_CT_VAL_ISOC = 3,
+
+       CAT_CL_SHIFT = 0,
+       CAT_CL_MASK = DIM2_MASK(6)
+};
+
+#endif /* DIM2_OS62420_H */
diff --git a/drivers/staging/most/dim2/sysfs.c b/drivers/staging/most/dim2/sysfs.c
new file mode 100644 (file)
index 0000000..ec1f4ce
--- /dev/null
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sysfs.c - MediaLB sysfs information
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include "sysfs.h"
+
+struct bus_attr {
+       struct attribute attr;
+       ssize_t (*show)(struct medialb_bus *bus, char *buf);
+       ssize_t (*store)(struct medialb_bus *bus, const char *buf,
+                        size_t count);
+};
+
+static ssize_t state_show(struct medialb_bus *bus, char *buf)
+{
+       bool state = dim2_sysfs_get_state_cb();
+
+       return sprintf(buf, "%s\n", state ? "locked" : "");
+}
+
+static struct bus_attr state_attr = __ATTR_RO(state);
+
+static struct attribute *bus_default_attrs[] = {
+       &state_attr.attr,
+       NULL,
+};
+
+static const struct attribute_group bus_attr_group = {
+       .attrs = bus_default_attrs,
+};
+
+static void bus_kobj_release(struct kobject *kobj)
+{
+}
+
+static ssize_t bus_kobj_attr_show(struct kobject *kobj, struct attribute *attr,
+                                 char *buf)
+{
+       struct medialb_bus *bus =
+               container_of(kobj, struct medialb_bus, kobj_group);
+       struct bus_attr *xattr = container_of(attr, struct bus_attr, attr);
+
+       if (!xattr->show)
+               return -EIO;
+
+       return xattr->show(bus, buf);
+}
+
+static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr,
+                                  const char *buf, size_t count)
+{
+       struct medialb_bus *bus =
+               container_of(kobj, struct medialb_bus, kobj_group);
+       struct bus_attr *xattr = container_of(attr, struct bus_attr, attr);
+
+       if (!xattr->store)
+               return -EIO;
+
+       return xattr->store(bus, buf, count);
+}
+
+static struct sysfs_ops const bus_kobj_sysfs_ops = {
+       .show = bus_kobj_attr_show,
+       .store = bus_kobj_attr_store,
+};
+
+static struct kobj_type bus_ktype = {
+       .release = bus_kobj_release,
+       .sysfs_ops = &bus_kobj_sysfs_ops,
+};
+
+int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj)
+{
+       int err;
+
+       kobject_init(&bus->kobj_group, &bus_ktype);
+       err = kobject_add(&bus->kobj_group, parent_kobj, "bus");
+       if (err) {
+               pr_err("kobject_add() failed: %d\n", err);
+               goto err_kobject_add;
+       }
+
+       err = sysfs_create_group(&bus->kobj_group, &bus_attr_group);
+       if (err) {
+               pr_err("sysfs_create_group() failed: %d\n", err);
+               goto err_create_group;
+       }
+
+       return 0;
+
+err_create_group:
+       kobject_put(&bus->kobj_group);
+
+err_kobject_add:
+       return err;
+}
+
+void dim2_sysfs_destroy(struct medialb_bus *bus)
+{
+       kobject_put(&bus->kobj_group);
+}
diff --git a/drivers/staging/most/dim2/sysfs.h b/drivers/staging/most/dim2/sysfs.h
new file mode 100644 (file)
index 0000000..a33ebd8
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sysfs.h - MediaLB sysfs information
+ *
+ * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
+ */
+
+/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
+
+#ifndef DIM2_SYSFS_H
+#define        DIM2_SYSFS_H
+
+#include <linux/kobject.h>
+
+struct medialb_bus {
+       struct kobject kobj_group;
+};
+
+struct dim2_hdm;
+
+int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj);
+void dim2_sysfs_destroy(struct medialb_bus *bus);
+
+/*
+ * callback,
+ * must deliver MediaLB state as true if locked or false if unlocked
+ */
+bool dim2_sysfs_get_state_cb(void);
+
+#endif /* DIM2_SYSFS_H */
diff --git a/drivers/staging/most/hdm-dim2/Kconfig b/drivers/staging/most/hdm-dim2/Kconfig
deleted file mode 100644 (file)
index 663bfeb..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# MediaLB configuration
-#
-
-config HDM_DIM2
-       tristate "DIM2 HDM"
-       depends on HAS_IOMEM
-
-       ---help---
-         Say Y here if you want to connect via MediaLB to network transceiver.
-         This device driver is platform dependent and needs an additional
-         platform driver to be installed. For more information contact
-         maintainer of this driver.
-
-         To compile this driver as a module, choose M here: the
-         module will be called hdm_dim2.
diff --git a/drivers/staging/most/hdm-dim2/dim2_errors.h b/drivers/staging/most/hdm-dim2/dim2_errors.h
deleted file mode 100644 (file)
index 8b90196..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_errors.h - Definitions of errors for DIM2 HAL API
- * (MediaLB, Device Interface Macro IP, OS62420)
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#ifndef _MOST_DIM_ERRORS_H
-#define _MOST_DIM_ERRORS_H
-
-/**
- * MOST DIM errors.
- */
-enum dim_errors_t {
-       /** Not an error */
-       DIM_NO_ERROR = 0,
-
-       /** Bad base address for DIM2 IP */
-       DIM_INIT_ERR_DIM_ADDR = 0x10,
-
-       /**< Bad MediaLB clock */
-       DIM_INIT_ERR_MLB_CLOCK,
-
-       /** Bad channel address */
-       DIM_INIT_ERR_CHANNEL_ADDRESS,
-
-       /** Out of DBR memory */
-       DIM_INIT_ERR_OUT_OF_MEMORY,
-
-       /** DIM API is called while DIM is not initialized successfully */
-       DIM_ERR_DRIVER_NOT_INITIALIZED = 0x20,
-
-       /**
-        * Configuration does not respect hardware limitations
-        * for isochronous or synchronous channels
-        */
-       DIM_ERR_BAD_CONFIG,
-
-       /**
-        * Buffer size does not respect hardware limitations
-        * for isochronous or synchronous channels
-        */
-       DIM_ERR_BAD_BUFFER_SIZE,
-
-       DIM_ERR_UNDERFLOW,
-
-       DIM_ERR_OVERFLOW,
-};
-
-#endif /* _MOST_DIM_ERRORS_H */
diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.c b/drivers/staging/most/hdm-dim2/dim2_hal.c
deleted file mode 100644 (file)
index f98ac93..0000000
+++ /dev/null
@@ -1,979 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_hal.c - DIM2 HAL implementation
- * (MediaLB, Device Interface Macro IP, OS62420)
- *
- * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG
- */
-
-/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
-
-#include "dim2_hal.h"
-#include "dim2_errors.h"
-#include "dim2_reg.h"
-#include <linux/stddef.h>
-#include <linux/kernel.h>
-
-/*
- * Size factor for isochronous DBR buffer.
- * Minimal value is 3.
- */
-#define ISOC_DBR_FACTOR 3u
-
-/*
- * Number of 32-bit units for DBR map.
- *
- * 1: block size is 512, max allocation is 16K
- * 2: block size is 256, max allocation is 8K
- * 4: block size is 128, max allocation is 4K
- * 8: block size is 64, max allocation is 2K
- *
- * Min allocated space is block size.
- * Max possible allocated space is 32 blocks.
- */
-#define DBR_MAP_SIZE 2
-
-/* -------------------------------------------------------------------------- */
-/* not configurable area */
-
-#define CDT 0x00
-#define ADT 0x40
-#define MLB_CAT 0x80
-#define AHB_CAT 0x88
-
-#define DBR_SIZE  (16 * 1024) /* specified by IP */
-#define DBR_BLOCK_SIZE  (DBR_SIZE / 32 / DBR_MAP_SIZE)
-
-#define ROUND_UP_TO(x, d)  (DIV_ROUND_UP(x, (d)) * (d))
-
-/* -------------------------------------------------------------------------- */
-/* generic helper functions and macros */
-
-static inline u32 bit_mask(u8 position)
-{
-       return (u32)1 << position;
-}
-
-static inline bool dim_on_error(u8 error_id, const char *error_message)
-{
-       dimcb_on_error(error_id, error_message);
-       return false;
-}
-
-/* -------------------------------------------------------------------------- */
-/* types and local variables */
-
-struct async_tx_dbr {
-       u8 ch_addr;
-       u16 rpc;
-       u16 wpc;
-       u16 rest_size;
-       u16 sz_queue[CDT0_RPC_MASK + 1];
-};
-
-struct lld_global_vars_t {
-       bool dim_is_initialized;
-       bool mcm_is_initialized;
-       struct dim2_regs __iomem *dim2; /* DIM2 core base address */
-       struct async_tx_dbr atx_dbr;
-       u32 fcnt;
-       u32 dbr_map[DBR_MAP_SIZE];
-};
-
-static struct lld_global_vars_t g = { false };
-
-/* -------------------------------------------------------------------------- */
-
-static int dbr_get_mask_size(u16 size)
-{
-       int i;
-
-       for (i = 0; i < 6; i++)
-               if (size <= (DBR_BLOCK_SIZE << i))
-                       return 1 << i;
-       return 0;
-}
-
-/**
- * Allocates DBR memory.
- * @param size Allocating memory size.
- * @return Offset in DBR memory by success or DBR_SIZE if out of memory.
- */
-static int alloc_dbr(u16 size)
-{
-       int mask_size;
-       int i, block_idx = 0;
-
-       if (size <= 0)
-               return DBR_SIZE; /* out of memory */
-
-       mask_size = dbr_get_mask_size(size);
-       if (mask_size == 0)
-               return DBR_SIZE; /* out of memory */
-
-       for (i = 0; i < DBR_MAP_SIZE; i++) {
-               u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
-               u32 mask = ~((~(u32)0) << blocks);
-
-               do {
-                       if ((g.dbr_map[i] & mask) == 0) {
-                               g.dbr_map[i] |= mask;
-                               return block_idx * DBR_BLOCK_SIZE;
-                       }
-                       block_idx += mask_size;
-                       /* do shift left with 2 steps in case mask_size == 32 */
-                       mask <<= mask_size - 1;
-               } while ((mask <<= 1) != 0);
-       }
-
-       return DBR_SIZE; /* out of memory */
-}
-
-static void free_dbr(int offs, int size)
-{
-       int block_idx = offs / DBR_BLOCK_SIZE;
-       u32 const blocks = DIV_ROUND_UP(size, DBR_BLOCK_SIZE);
-       u32 mask = ~((~(u32)0) << blocks);
-
-       mask <<= block_idx % 32;
-       g.dbr_map[block_idx / 32] &= ~mask;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static void dim2_transfer_madr(u32 val)
-{
-       dimcb_io_write(&g.dim2->MADR, val);
-
-       /* wait for transfer completion */
-       while ((dimcb_io_read(&g.dim2->MCTL) & 1) != 1)
-               continue;
-
-       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
-}
-
-static void dim2_clear_dbr(u16 addr, u16 size)
-{
-       enum { MADR_TB_BIT = 30, MADR_WNR_BIT = 31 };
-
-       u16 const end_addr = addr + size;
-       u32 const cmd = bit_mask(MADR_WNR_BIT) | bit_mask(MADR_TB_BIT);
-
-       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
-       dimcb_io_write(&g.dim2->MDAT0, 0);
-
-       for (; addr < end_addr; addr++)
-               dim2_transfer_madr(cmd | addr);
-}
-
-static u32 dim2_read_ctr(u32 ctr_addr, u16 mdat_idx)
-{
-       dim2_transfer_madr(ctr_addr);
-
-       return dimcb_io_read((&g.dim2->MDAT0) + mdat_idx);
-}
-
-static void dim2_write_ctr_mask(u32 ctr_addr, const u32 *mask, const u32 *value)
-{
-       enum { MADR_WNR_BIT = 31 };
-
-       dimcb_io_write(&g.dim2->MCTL, 0);   /* clear transfer complete */
-
-       if (mask[0] != 0)
-               dimcb_io_write(&g.dim2->MDAT0, value[0]);
-       if (mask[1] != 0)
-               dimcb_io_write(&g.dim2->MDAT1, value[1]);
-       if (mask[2] != 0)
-               dimcb_io_write(&g.dim2->MDAT2, value[2]);
-       if (mask[3] != 0)
-               dimcb_io_write(&g.dim2->MDAT3, value[3]);
-
-       dimcb_io_write(&g.dim2->MDWE0, mask[0]);
-       dimcb_io_write(&g.dim2->MDWE1, mask[1]);
-       dimcb_io_write(&g.dim2->MDWE2, mask[2]);
-       dimcb_io_write(&g.dim2->MDWE3, mask[3]);
-
-       dim2_transfer_madr(bit_mask(MADR_WNR_BIT) | ctr_addr);
-}
-
-static inline void dim2_write_ctr(u32 ctr_addr, const u32 *value)
-{
-       u32 const mask[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
-
-       dim2_write_ctr_mask(ctr_addr, mask, value);
-}
-
-static inline void dim2_clear_ctr(u32 ctr_addr)
-{
-       u32 const value[4] = { 0, 0, 0, 0 };
-
-       dim2_write_ctr(ctr_addr, value);
-}
-
-static void dim2_configure_cat(u8 cat_base, u8 ch_addr, u8 ch_type,
-                              bool read_not_write)
-{
-       bool isoc_fce = ch_type == CAT_CT_VAL_ISOC;
-       bool sync_mfe = ch_type == CAT_CT_VAL_SYNC;
-       u16 const cat =
-               (read_not_write << CAT_RNW_BIT) |
-               (ch_type << CAT_CT_SHIFT) |
-               (ch_addr << CAT_CL_SHIFT) |
-               (isoc_fce << CAT_FCE_BIT) |
-               (sync_mfe << CAT_MFE_BIT) |
-               (false << CAT_MT_BIT) |
-               (true << CAT_CE_BIT);
-       u8 const ctr_addr = cat_base + ch_addr / 8;
-       u8 const idx = (ch_addr % 8) / 2;
-       u8 const shift = (ch_addr % 2) * 16;
-       u32 mask[4] = { 0, 0, 0, 0 };
-       u32 value[4] = { 0, 0, 0, 0 };
-
-       mask[idx] = (u32)0xFFFF << shift;
-       value[idx] = cat << shift;
-       dim2_write_ctr_mask(ctr_addr, mask, value);
-}
-
-static void dim2_clear_cat(u8 cat_base, u8 ch_addr)
-{
-       u8 const ctr_addr = cat_base + ch_addr / 8;
-       u8 const idx = (ch_addr % 8) / 2;
-       u8 const shift = (ch_addr % 2) * 16;
-       u32 mask[4] = { 0, 0, 0, 0 };
-       u32 value[4] = { 0, 0, 0, 0 };
-
-       mask[idx] = (u32)0xFFFF << shift;
-       dim2_write_ctr_mask(ctr_addr, mask, value);
-}
-
-static void dim2_configure_cdt(u8 ch_addr, u16 dbr_address, u16 hw_buffer_size,
-                              u16 packet_length)
-{
-       u32 cdt[4] = { 0, 0, 0, 0 };
-
-       if (packet_length)
-               cdt[1] = ((packet_length - 1) << CDT1_BS_ISOC_SHIFT);
-
-       cdt[3] =
-               ((hw_buffer_size - 1) << CDT3_BD_SHIFT) |
-               (dbr_address << CDT3_BA_SHIFT);
-       dim2_write_ctr(CDT + ch_addr, cdt);
-}
-
-static u16 dim2_rpc(u8 ch_addr)
-{
-       u32 cdt0 = dim2_read_ctr(CDT + ch_addr, 0);
-
-       return (cdt0 >> CDT0_RPC_SHIFT) & CDT0_RPC_MASK;
-}
-
-static void dim2_clear_cdt(u8 ch_addr)
-{
-       u32 cdt[4] = { 0, 0, 0, 0 };
-
-       dim2_write_ctr(CDT + ch_addr, cdt);
-}
-
-static void dim2_configure_adt(u8 ch_addr)
-{
-       u32 adt[4] = { 0, 0, 0, 0 };
-
-       adt[0] =
-               (true << ADT0_CE_BIT) |
-               (true << ADT0_LE_BIT) |
-               (0 << ADT0_PG_BIT);
-
-       dim2_write_ctr(ADT + ch_addr, adt);
-}
-
-static void dim2_clear_adt(u8 ch_addr)
-{
-       u32 adt[4] = { 0, 0, 0, 0 };
-
-       dim2_write_ctr(ADT + ch_addr, adt);
-}
-
-static void dim2_start_ctrl_async(u8 ch_addr, u8 idx, u32 buf_addr,
-                                 u16 buffer_size)
-{
-       u8 const shift = idx * 16;
-
-       u32 mask[4] = { 0, 0, 0, 0 };
-       u32 adt[4] = { 0, 0, 0, 0 };
-
-       mask[1] =
-               bit_mask(ADT1_PS_BIT + shift) |
-               bit_mask(ADT1_RDY_BIT + shift) |
-               (ADT1_CTRL_ASYNC_BD_MASK << (ADT1_BD_SHIFT + shift));
-       adt[1] =
-               (true << (ADT1_PS_BIT + shift)) |
-               (true << (ADT1_RDY_BIT + shift)) |
-               ((buffer_size - 1) << (ADT1_BD_SHIFT + shift));
-
-       mask[idx + 2] = 0xFFFFFFFF;
-       adt[idx + 2] = buf_addr;
-
-       dim2_write_ctr_mask(ADT + ch_addr, mask, adt);
-}
-
-static void dim2_start_isoc_sync(u8 ch_addr, u8 idx, u32 buf_addr,
-                                u16 buffer_size)
-{
-       u8 const shift = idx * 16;
-
-       u32 mask[4] = { 0, 0, 0, 0 };
-       u32 adt[4] = { 0, 0, 0, 0 };
-
-       mask[1] =
-               bit_mask(ADT1_RDY_BIT + shift) |
-               (ADT1_ISOC_SYNC_BD_MASK << (ADT1_BD_SHIFT + shift));
-       adt[1] =
-               (true << (ADT1_RDY_BIT + shift)) |
-               ((buffer_size - 1) << (ADT1_BD_SHIFT + shift));
-
-       mask[idx + 2] = 0xFFFFFFFF;
-       adt[idx + 2] = buf_addr;
-
-       dim2_write_ctr_mask(ADT + ch_addr, mask, adt);
-}
-
-static void dim2_clear_ctram(void)
-{
-       u32 ctr_addr;
-
-       for (ctr_addr = 0; ctr_addr < 0x90; ctr_addr++)
-               dim2_clear_ctr(ctr_addr);
-}
-
-static void dim2_configure_channel(
-       u8 ch_addr, u8 type, u8 is_tx, u16 dbr_address, u16 hw_buffer_size,
-       u16 packet_length)
-{
-       dim2_configure_cdt(ch_addr, dbr_address, hw_buffer_size, packet_length);
-       dim2_configure_cat(MLB_CAT, ch_addr, type, is_tx ? 1 : 0);
-
-       dim2_configure_adt(ch_addr);
-       dim2_configure_cat(AHB_CAT, ch_addr, type, is_tx ? 0 : 1);
-
-       /* unmask interrupt for used channel, enable mlb_sys_int[0] interrupt */
-       dimcb_io_write(&g.dim2->ACMR0,
-                      dimcb_io_read(&g.dim2->ACMR0) | bit_mask(ch_addr));
-}
-
-static void dim2_clear_channel(u8 ch_addr)
-{
-       /* mask interrupt for used channel, disable mlb_sys_int[0] interrupt */
-       dimcb_io_write(&g.dim2->ACMR0,
-                      dimcb_io_read(&g.dim2->ACMR0) & ~bit_mask(ch_addr));
-
-       dim2_clear_cat(AHB_CAT, ch_addr);
-       dim2_clear_adt(ch_addr);
-
-       dim2_clear_cat(MLB_CAT, ch_addr);
-       dim2_clear_cdt(ch_addr);
-
-       /* clear channel status bit */
-       dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
-}
-
-/* -------------------------------------------------------------------------- */
-/* trace async tx dbr fill state */
-
-static inline u16 norm_pc(u16 pc)
-{
-       return pc & CDT0_RPC_MASK;
-}
-
-static void dbrcnt_init(u8 ch_addr, u16 dbr_size)
-{
-       g.atx_dbr.rest_size = dbr_size;
-       g.atx_dbr.rpc = dim2_rpc(ch_addr);
-       g.atx_dbr.wpc = g.atx_dbr.rpc;
-}
-
-static void dbrcnt_enq(int buf_sz)
-{
-       g.atx_dbr.rest_size -= buf_sz;
-       g.atx_dbr.sz_queue[norm_pc(g.atx_dbr.wpc)] = buf_sz;
-       g.atx_dbr.wpc++;
-}
-
-u16 dim_dbr_space(struct dim_channel *ch)
-{
-       u16 cur_rpc;
-       struct async_tx_dbr *dbr = &g.atx_dbr;
-
-       if (ch->addr != dbr->ch_addr)
-               return 0xFFFF;
-
-       cur_rpc = dim2_rpc(ch->addr);
-
-       while (norm_pc(dbr->rpc) != cur_rpc) {
-               dbr->rest_size += dbr->sz_queue[norm_pc(dbr->rpc)];
-               dbr->rpc++;
-       }
-
-       if ((u16)(dbr->wpc - dbr->rpc) >= CDT0_RPC_MASK)
-               return 0;
-
-       return dbr->rest_size;
-}
-
-/* -------------------------------------------------------------------------- */
-/* channel state helpers */
-
-static void state_init(struct int_ch_state *state)
-{
-       state->request_counter = 0;
-       state->service_counter = 0;
-
-       state->idx1 = 0;
-       state->idx2 = 0;
-       state->level = 0;
-}
-
-/* -------------------------------------------------------------------------- */
-/* macro helper functions */
-
-static inline bool check_channel_address(u32 ch_address)
-{
-       return ch_address > 0 && (ch_address % 2) == 0 &&
-              (ch_address / 2) <= (u32)CAT_CL_MASK;
-}
-
-static inline bool check_packet_length(u32 packet_length)
-{
-       u16 const max_size = ((u16)CDT3_BD_ISOC_MASK + 1u) / ISOC_DBR_FACTOR;
-
-       if (packet_length <= 0)
-               return false; /* too small */
-
-       if (packet_length > max_size)
-               return false; /* too big */
-
-       if (packet_length - 1u > (u32)CDT1_BS_ISOC_MASK)
-               return false; /* too big */
-
-       return true;
-}
-
-static inline bool check_bytes_per_frame(u32 bytes_per_frame)
-{
-       u16 const bd_factor = g.fcnt + 2;
-       u16 const max_size = ((u16)CDT3_BD_MASK + 1u) >> bd_factor;
-
-       if (bytes_per_frame <= 0)
-               return false; /* too small */
-
-       if (bytes_per_frame > max_size)
-               return false; /* too big */
-
-       return true;
-}
-
-static inline u16 norm_ctrl_async_buffer_size(u16 buf_size)
-{
-       u16 const max_size = (u16)ADT1_CTRL_ASYNC_BD_MASK + 1u;
-
-       if (buf_size > max_size)
-               return max_size;
-
-       return buf_size;
-}
-
-static inline u16 norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
-{
-       u16 n;
-       u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u;
-
-       if (buf_size > max_size)
-               buf_size = max_size;
-
-       n = buf_size / packet_length;
-
-       if (n < 2u)
-               return 0; /* too small buffer for given packet_length */
-
-       return packet_length * n;
-}
-
-static inline u16 norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
-{
-       u16 n;
-       u16 const max_size = (u16)ADT1_ISOC_SYNC_BD_MASK + 1u;
-       u32 const unit = bytes_per_frame << g.fcnt;
-
-       if (buf_size > max_size)
-               buf_size = max_size;
-
-       n = buf_size / unit;
-
-       if (n < 1u)
-               return 0; /* too small buffer for given bytes_per_frame */
-
-       return unit * n;
-}
-
-static void dim2_cleanup(void)
-{
-       /* disable MediaLB */
-       dimcb_io_write(&g.dim2->MLBC0, false << MLBC0_MLBEN_BIT);
-
-       dim2_clear_ctram();
-
-       /* disable mlb_int interrupt */
-       dimcb_io_write(&g.dim2->MIEN, 0);
-
-       /* clear status for all dma channels */
-       dimcb_io_write(&g.dim2->ACSR0, 0xFFFFFFFF);
-       dimcb_io_write(&g.dim2->ACSR1, 0xFFFFFFFF);
-
-       /* mask interrupts for all channels */
-       dimcb_io_write(&g.dim2->ACMR0, 0);
-       dimcb_io_write(&g.dim2->ACMR1, 0);
-}
-
-static void dim2_initialize(bool enable_6pin, u8 mlb_clock)
-{
-       dim2_cleanup();
-
-       /* configure and enable MediaLB */
-       dimcb_io_write(&g.dim2->MLBC0,
-                      enable_6pin << MLBC0_MLBPEN_BIT |
-                      mlb_clock << MLBC0_MLBCLK_SHIFT |
-                      g.fcnt << MLBC0_FCNT_SHIFT |
-                      true << MLBC0_MLBEN_BIT);
-
-       /* activate all HBI channels */
-       dimcb_io_write(&g.dim2->HCMR0, 0xFFFFFFFF);
-       dimcb_io_write(&g.dim2->HCMR1, 0xFFFFFFFF);
-
-       /* enable HBI */
-       dimcb_io_write(&g.dim2->HCTL, bit_mask(HCTL_EN_BIT));
-
-       /* configure DMA */
-       dimcb_io_write(&g.dim2->ACTL,
-                      ACTL_DMA_MODE_VAL_DMA_MODE_1 << ACTL_DMA_MODE_BIT |
-                      true << ACTL_SCE_BIT);
-}
-
-static bool dim2_is_mlb_locked(void)
-{
-       u32 const mask0 = bit_mask(MLBC0_MLBLK_BIT);
-       u32 const mask1 = bit_mask(MLBC1_CLKMERR_BIT) |
-                         bit_mask(MLBC1_LOCKERR_BIT);
-       u32 const c1 = dimcb_io_read(&g.dim2->MLBC1);
-       u32 const nda_mask = (u32)MLBC1_NDA_MASK << MLBC1_NDA_SHIFT;
-
-       dimcb_io_write(&g.dim2->MLBC1, c1 & nda_mask);
-       return (dimcb_io_read(&g.dim2->MLBC1) & mask1) == 0 &&
-              (dimcb_io_read(&g.dim2->MLBC0) & mask0) != 0;
-}
-
-/* -------------------------------------------------------------------------- */
-/* channel help routines */
-
-static inline bool service_channel(u8 ch_addr, u8 idx)
-{
-       u8 const shift = idx * 16;
-       u32 const adt1 = dim2_read_ctr(ADT + ch_addr, 1);
-       u32 mask[4] = { 0, 0, 0, 0 };
-       u32 adt_w[4] = { 0, 0, 0, 0 };
-
-       if (((adt1 >> (ADT1_DNE_BIT + shift)) & 1) == 0)
-               return false;
-
-       mask[1] =
-               bit_mask(ADT1_DNE_BIT + shift) |
-               bit_mask(ADT1_ERR_BIT + shift) |
-               bit_mask(ADT1_RDY_BIT + shift);
-       dim2_write_ctr_mask(ADT + ch_addr, mask, adt_w);
-
-       /* clear channel status bit */
-       dimcb_io_write(&g.dim2->ACSR0, bit_mask(ch_addr));
-
-       return true;
-}
-
-/* -------------------------------------------------------------------------- */
-/* channel init routines */
-
-static void isoc_init(struct dim_channel *ch, u8 ch_addr, u16 packet_length)
-{
-       state_init(&ch->state);
-
-       ch->addr = ch_addr;
-
-       ch->packet_length = packet_length;
-       ch->bytes_per_frame = 0;
-       ch->done_sw_buffers_number = 0;
-}
-
-static void sync_init(struct dim_channel *ch, u8 ch_addr, u16 bytes_per_frame)
-{
-       state_init(&ch->state);
-
-       ch->addr = ch_addr;
-
-       ch->packet_length = 0;
-       ch->bytes_per_frame = bytes_per_frame;
-       ch->done_sw_buffers_number = 0;
-}
-
-static void channel_init(struct dim_channel *ch, u8 ch_addr)
-{
-       state_init(&ch->state);
-
-       ch->addr = ch_addr;
-
-       ch->packet_length = 0;
-       ch->bytes_per_frame = 0;
-       ch->done_sw_buffers_number = 0;
-}
-
-/* returns true if channel interrupt state is cleared */
-static bool channel_service_interrupt(struct dim_channel *ch)
-{
-       struct int_ch_state *const state = &ch->state;
-
-       if (!service_channel(ch->addr, state->idx2))
-               return false;
-
-       state->idx2 ^= 1;
-       state->request_counter++;
-       return true;
-}
-
-static bool channel_start(struct dim_channel *ch, u32 buf_addr, u16 buf_size)
-{
-       struct int_ch_state *const state = &ch->state;
-
-       if (buf_size <= 0)
-               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE, "Bad buffer size");
-
-       if (ch->packet_length == 0 && ch->bytes_per_frame == 0 &&
-           buf_size != norm_ctrl_async_buffer_size(buf_size))
-               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
-                                   "Bad control/async buffer size");
-
-       if (ch->packet_length &&
-           buf_size != norm_isoc_buffer_size(buf_size, ch->packet_length))
-               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
-                                   "Bad isochronous buffer size");
-
-       if (ch->bytes_per_frame &&
-           buf_size != norm_sync_buffer_size(buf_size, ch->bytes_per_frame))
-               return dim_on_error(DIM_ERR_BAD_BUFFER_SIZE,
-                                   "Bad synchronous buffer size");
-
-       if (state->level >= 2u)
-               return dim_on_error(DIM_ERR_OVERFLOW, "Channel overflow");
-
-       ++state->level;
-
-       if (ch->addr == g.atx_dbr.ch_addr)
-               dbrcnt_enq(buf_size);
-
-       if (ch->packet_length || ch->bytes_per_frame)
-               dim2_start_isoc_sync(ch->addr, state->idx1, buf_addr, buf_size);
-       else
-               dim2_start_ctrl_async(ch->addr, state->idx1, buf_addr,
-                                     buf_size);
-       state->idx1 ^= 1;
-
-       return true;
-}
-
-static u8 channel_service(struct dim_channel *ch)
-{
-       struct int_ch_state *const state = &ch->state;
-
-       if (state->service_counter != state->request_counter) {
-               state->service_counter++;
-               if (state->level == 0)
-                       return DIM_ERR_UNDERFLOW;
-
-               --state->level;
-               ch->done_sw_buffers_number++;
-       }
-
-       return DIM_NO_ERROR;
-}
-
-static bool channel_detach_buffers(struct dim_channel *ch, u16 buffers_number)
-{
-       if (buffers_number > ch->done_sw_buffers_number)
-               return dim_on_error(DIM_ERR_UNDERFLOW, "Channel underflow");
-
-       ch->done_sw_buffers_number -= buffers_number;
-       return true;
-}
-
-/* -------------------------------------------------------------------------- */
-/* API */
-
-u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock,
-              u32 fcnt)
-{
-       g.dim_is_initialized = false;
-
-       if (!dim_base_address)
-               return DIM_INIT_ERR_DIM_ADDR;
-
-       /* MediaLB clock: 0 - 256 fs, 1 - 512 fs, 2 - 1024 fs, 3 - 2048 fs */
-       /* MediaLB clock: 4 - 3072 fs, 5 - 4096 fs, 6 - 6144 fs, 7 - 8192 fs */
-       if (mlb_clock >= 8)
-               return DIM_INIT_ERR_MLB_CLOCK;
-
-       if (fcnt > MLBC0_FCNT_MAX_VAL)
-               return DIM_INIT_ERR_MLB_CLOCK;
-
-       g.dim2 = dim_base_address;
-       g.fcnt = fcnt;
-       g.dbr_map[0] = 0;
-       g.dbr_map[1] = 0;
-
-       dim2_initialize(mlb_clock >= 3, mlb_clock);
-
-       g.dim_is_initialized = true;
-
-       return DIM_NO_ERROR;
-}
-
-void dim_shutdown(void)
-{
-       g.dim_is_initialized = false;
-       dim2_cleanup();
-}
-
-bool dim_get_lock_state(void)
-{
-       return dim2_is_mlb_locked();
-}
-
-static u8 init_ctrl_async(struct dim_channel *ch, u8 type, u8 is_tx,
-                         u16 ch_address, u16 hw_buffer_size)
-{
-       if (!g.dim_is_initialized || !ch)
-               return DIM_ERR_DRIVER_NOT_INITIALIZED;
-
-       if (!check_channel_address(ch_address))
-               return DIM_INIT_ERR_CHANNEL_ADDRESS;
-
-       ch->dbr_size = ROUND_UP_TO(hw_buffer_size, DBR_BLOCK_SIZE);
-       ch->dbr_addr = alloc_dbr(ch->dbr_size);
-       if (ch->dbr_addr >= DBR_SIZE)
-               return DIM_INIT_ERR_OUT_OF_MEMORY;
-
-       channel_init(ch, ch_address / 2);
-
-       dim2_configure_channel(ch->addr, type, is_tx,
-                              ch->dbr_addr, ch->dbr_size, 0);
-
-       return DIM_NO_ERROR;
-}
-
-void dim_service_mlb_int_irq(void)
-{
-       dimcb_io_write(&g.dim2->MS0, 0);
-       dimcb_io_write(&g.dim2->MS1, 0);
-}
-
-u16 dim_norm_ctrl_async_buffer_size(u16 buf_size)
-{
-       return norm_ctrl_async_buffer_size(buf_size);
-}
-
-/**
- * Retrieves maximal possible correct buffer size for isochronous data type
- * conform to given packet length and not bigger than given buffer size.
- *
- * Returns non-zero correct buffer size or zero by error.
- */
-u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length)
-{
-       if (!check_packet_length(packet_length))
-               return 0;
-
-       return norm_isoc_buffer_size(buf_size, packet_length);
-}
-
-/**
- * Retrieves maximal possible correct buffer size for synchronous data type
- * conform to given bytes per frame and not bigger than given buffer size.
- *
- * Returns non-zero correct buffer size or zero by error.
- */
-u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame)
-{
-       if (!check_bytes_per_frame(bytes_per_frame))
-               return 0;
-
-       return norm_sync_buffer_size(buf_size, bytes_per_frame);
-}
-
-u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                   u16 max_buffer_size)
-{
-       return init_ctrl_async(ch, CAT_CT_VAL_CONTROL, is_tx, ch_address,
-                              max_buffer_size);
-}
-
-u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                 u16 max_buffer_size)
-{
-       u8 ret = init_ctrl_async(ch, CAT_CT_VAL_ASYNC, is_tx, ch_address,
-                                max_buffer_size);
-
-       if (is_tx && !g.atx_dbr.ch_addr) {
-               g.atx_dbr.ch_addr = ch->addr;
-               dbrcnt_init(ch->addr, ch->dbr_size);
-               dimcb_io_write(&g.dim2->MIEN, bit_mask(20));
-       }
-
-       return ret;
-}
-
-u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                u16 packet_length)
-{
-       if (!g.dim_is_initialized || !ch)
-               return DIM_ERR_DRIVER_NOT_INITIALIZED;
-
-       if (!check_channel_address(ch_address))
-               return DIM_INIT_ERR_CHANNEL_ADDRESS;
-
-       if (!check_packet_length(packet_length))
-               return DIM_ERR_BAD_CONFIG;
-
-       ch->dbr_size = packet_length * ISOC_DBR_FACTOR;
-       ch->dbr_addr = alloc_dbr(ch->dbr_size);
-       if (ch->dbr_addr >= DBR_SIZE)
-               return DIM_INIT_ERR_OUT_OF_MEMORY;
-
-       isoc_init(ch, ch_address / 2, packet_length);
-
-       dim2_configure_channel(ch->addr, CAT_CT_VAL_ISOC, is_tx, ch->dbr_addr,
-                              ch->dbr_size, packet_length);
-
-       return DIM_NO_ERROR;
-}
-
-u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                u16 bytes_per_frame)
-{
-       u16 bd_factor = g.fcnt + 2;
-
-       if (!g.dim_is_initialized || !ch)
-               return DIM_ERR_DRIVER_NOT_INITIALIZED;
-
-       if (!check_channel_address(ch_address))
-               return DIM_INIT_ERR_CHANNEL_ADDRESS;
-
-       if (!check_bytes_per_frame(bytes_per_frame))
-               return DIM_ERR_BAD_CONFIG;
-
-       ch->dbr_size = bytes_per_frame << bd_factor;
-       ch->dbr_addr = alloc_dbr(ch->dbr_size);
-       if (ch->dbr_addr >= DBR_SIZE)
-               return DIM_INIT_ERR_OUT_OF_MEMORY;
-
-       sync_init(ch, ch_address / 2, bytes_per_frame);
-
-       dim2_clear_dbr(ch->dbr_addr, ch->dbr_size);
-       dim2_configure_channel(ch->addr, CAT_CT_VAL_SYNC, is_tx,
-                              ch->dbr_addr, ch->dbr_size, 0);
-
-       return DIM_NO_ERROR;
-}
-
-u8 dim_destroy_channel(struct dim_channel *ch)
-{
-       if (!g.dim_is_initialized || !ch)
-               return DIM_ERR_DRIVER_NOT_INITIALIZED;
-
-       if (ch->addr == g.atx_dbr.ch_addr) {
-               dimcb_io_write(&g.dim2->MIEN, 0);
-               g.atx_dbr.ch_addr = 0;
-       }
-
-       dim2_clear_channel(ch->addr);
-       if (ch->dbr_addr < DBR_SIZE)
-               free_dbr(ch->dbr_addr, ch->dbr_size);
-       ch->dbr_addr = DBR_SIZE;
-
-       return DIM_NO_ERROR;
-}
-
-void dim_service_ahb_int_irq(struct dim_channel *const *channels)
-{
-       bool state_changed;
-
-       if (!g.dim_is_initialized) {
-               dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
-                            "DIM is not initialized");
-               return;
-       }
-
-       if (!channels) {
-               dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED, "Bad channels");
-               return;
-       }
-
-       /*
-        * Use while-loop and a flag to make sure the age is changed back at
-        * least once, otherwise the interrupt may never come if CPU generates
-        * interrupt on changing age.
-        * This cycle runs not more than number of channels, because
-        * channel_service_interrupt() routine doesn't start the channel again.
-        */
-       do {
-               struct dim_channel *const *ch = channels;
-
-               state_changed = false;
-
-               while (*ch) {
-                       state_changed |= channel_service_interrupt(*ch);
-                       ++ch;
-               }
-       } while (state_changed);
-}
-
-u8 dim_service_channel(struct dim_channel *ch)
-{
-       if (!g.dim_is_initialized || !ch)
-               return DIM_ERR_DRIVER_NOT_INITIALIZED;
-
-       return channel_service(ch);
-}
-
-struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
-                                            struct dim_ch_state_t *state_ptr)
-{
-       if (!ch || !state_ptr)
-               return NULL;
-
-       state_ptr->ready = ch->state.level < 2;
-       state_ptr->done_buffers = ch->done_sw_buffers_number;
-
-       return state_ptr;
-}
-
-bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
-                       u16 buffer_size)
-{
-       if (!ch)
-               return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
-                                   "Bad channel");
-
-       return channel_start(ch, buffer_addr, buffer_size);
-}
-
-bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number)
-{
-       if (!ch)
-               return dim_on_error(DIM_ERR_DRIVER_NOT_INITIALIZED,
-                                   "Bad channel");
-
-       return channel_detach_buffers(ch, buffers_number);
-}
diff --git a/drivers/staging/most/hdm-dim2/dim2_hal.h b/drivers/staging/most/hdm-dim2/dim2_hal.h
deleted file mode 100644 (file)
index fce9ae9..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_hal.h - DIM2 HAL interface
- * (MediaLB, Device Interface Macro IP, OS62420)
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#ifndef _DIM2_HAL_H
-#define _DIM2_HAL_H
-
-#include <linux/types.h>
-#include "dim2_reg.h"
-
-/*
- * The values below are specified in the hardware specification.
- * So, they should not be changed until the hardware specification changes.
- */
-enum mlb_clk_speed {
-       CLK_256FS = 0,
-       CLK_512FS = 1,
-       CLK_1024FS = 2,
-       CLK_2048FS = 3,
-       CLK_3072FS = 4,
-       CLK_4096FS = 5,
-       CLK_6144FS = 6,
-       CLK_8192FS = 7,
-};
-
-struct dim_ch_state_t {
-       bool ready; /* Shows readiness to enqueue next buffer */
-       u16 done_buffers; /* Number of completed buffers */
-};
-
-struct int_ch_state {
-       /* changed only in interrupt context */
-       volatile int request_counter;
-
-       /* changed only in task context */
-       volatile int service_counter;
-
-       u8 idx1;
-       u8 idx2;
-       u8 level; /* [0..2], buffering level */
-};
-
-struct dim_channel {
-       struct int_ch_state state;
-       u8 addr;
-       u16 dbr_addr;
-       u16 dbr_size;
-       u16 packet_length; /*< Isochronous packet length in bytes. */
-       u16 bytes_per_frame; /*< Synchronous bytes per frame. */
-       u16 done_sw_buffers_number; /*< Done software buffers number. */
-};
-
-u8 dim_startup(struct dim2_regs __iomem *dim_base_address, u32 mlb_clock,
-              u32 fcnt);
-
-void dim_shutdown(void);
-
-bool dim_get_lock_state(void);
-
-u16 dim_norm_ctrl_async_buffer_size(u16 buf_size);
-
-u16 dim_norm_isoc_buffer_size(u16 buf_size, u16 packet_length);
-
-u16 dim_norm_sync_buffer_size(u16 buf_size, u16 bytes_per_frame);
-
-u8 dim_init_control(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                   u16 max_buffer_size);
-
-u8 dim_init_async(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                 u16 max_buffer_size);
-
-u8 dim_init_isoc(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                u16 packet_length);
-
-u8 dim_init_sync(struct dim_channel *ch, u8 is_tx, u16 ch_address,
-                u16 bytes_per_frame);
-
-u8 dim_destroy_channel(struct dim_channel *ch);
-
-void dim_service_mlb_int_irq(void);
-
-void dim_service_ahb_int_irq(struct dim_channel *const *channels);
-
-u8 dim_service_channel(struct dim_channel *ch);
-
-struct dim_ch_state_t *dim_get_channel_state(struct dim_channel *ch,
-                                            struct dim_ch_state_t *state_ptr);
-
-u16 dim_dbr_space(struct dim_channel *ch);
-
-bool dim_enqueue_buffer(struct dim_channel *ch, u32 buffer_addr,
-                       u16 buffer_size);
-
-bool dim_detach_buffers(struct dim_channel *ch, u16 buffers_number);
-
-u32 dimcb_io_read(u32 __iomem *ptr32);
-
-void dimcb_io_write(u32 __iomem *ptr32, u32 value);
-
-void dimcb_on_error(u8 error_id, const char *error_message);
-
-#endif /* _DIM2_HAL_H */
diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.c b/drivers/staging/most/hdm-dim2/dim2_hdm.c
deleted file mode 100644 (file)
index fedd2d0..0000000
+++ /dev/null
@@ -1,912 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_hdm.c - MediaLB DIM2 Hardware Dependent Module
- *
- * Copyright (C) 2015-2016, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/printk.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-
-#include "most/core.h"
-#include "dim2_hal.h"
-#include "dim2_hdm.h"
-#include "dim2_errors.h"
-#include "dim2_sysfs.h"
-
-#define DMA_CHANNELS (32 - 1)  /* channel 0 is a system channel */
-
-#define MAX_BUFFERS_PACKET      32
-#define MAX_BUFFERS_STREAMING   32
-#define MAX_BUF_SIZE_PACKET     2048
-#define MAX_BUF_SIZE_STREAMING  (8 * 1024)
-
-/* command line parameter to select clock speed */
-static char *clock_speed;
-module_param(clock_speed, charp, 0000);
-MODULE_PARM_DESC(clock_speed, "MediaLB Clock Speed");
-
-/*
- * The parameter representing the number of frames per sub-buffer for
- * synchronous channels.  Valid values: [0 .. 6].
- *
- * The values 0, 1, 2, 3, 4, 5, 6 represent corresponding number of frames per
- * sub-buffer 1, 2, 4, 8, 16, 32, 64.
- */
-static u8 fcnt = 4;  /* (1 << fcnt) frames per subbuffer */
-module_param(fcnt, byte, 0000);
-MODULE_PARM_DESC(fcnt, "Num of frames per sub-buffer for sync channels as a power of 2");
-
-static DEFINE_SPINLOCK(dim_lock);
-
-static void dim2_tasklet_fn(unsigned long data);
-static DECLARE_TASKLET(dim2_tasklet, dim2_tasklet_fn, 0);
-
-/**
- * struct hdm_channel - private structure to keep channel specific data
- * @is_initialized: identifier to know whether the channel is initialized
- * @ch: HAL specific channel data
- * @pending_list: list to keep MBO's before starting transfer
- * @started_list: list to keep MBO's after starting transfer
- * @direction: channel direction (TX or RX)
- * @data_type: channel data type
- */
-struct hdm_channel {
-       char name[sizeof "caNNN"];
-       bool is_initialized;
-       struct dim_channel ch;
-       struct list_head pending_list;  /* before dim_enqueue_buffer() */
-       struct list_head started_list;  /* after dim_enqueue_buffer() */
-       enum most_channel_direction direction;
-       enum most_channel_data_type data_type;
-};
-
-/**
- * struct dim2_hdm - private structure to keep interface specific data
- * @hch: an array of channel specific data
- * @most_iface: most interface structure
- * @capabilities: an array of channel capability data
- * @io_base: I/O register base address
- * @clk_speed: user selectable (through command line parameter) clock speed
- * @netinfo_task: thread to deliver network status
- * @netinfo_waitq: waitq for the thread to sleep
- * @deliver_netinfo: to identify whether network status received
- * @mac_addrs: INIC mac address
- * @link_state: network link state
- * @atx_idx: index of async tx channel
- */
-struct dim2_hdm {
-       struct hdm_channel hch[DMA_CHANNELS];
-       struct most_channel_capability capabilities[DMA_CHANNELS];
-       struct most_interface most_iface;
-       char name[16 + sizeof "dim2-"];
-       void __iomem *io_base;
-       int clk_speed;
-       struct task_struct *netinfo_task;
-       wait_queue_head_t netinfo_waitq;
-       int deliver_netinfo;
-       unsigned char mac_addrs[6];
-       unsigned char link_state;
-       int atx_idx;
-       struct medialb_bus bus;
-       void (*on_netinfo)(struct most_interface *,
-                          unsigned char, unsigned char *);
-};
-
-#define iface_to_hdm(iface) container_of(iface, struct dim2_hdm, most_iface)
-
-/* Macro to identify a network status message */
-#define PACKET_IS_NET_INFO(p)  \
-       (((p)[1] == 0x18) && ((p)[2] == 0x05) && ((p)[3] == 0x0C) && \
-        ((p)[13] == 0x3C) && ((p)[14] == 0x00) && ((p)[15] == 0x0A))
-
-bool dim2_sysfs_get_state_cb(void)
-{
-       bool state;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dim_lock, flags);
-       state = dim_get_lock_state();
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       return state;
-}
-
-/**
- * dimcb_io_read - callback from HAL to read an I/O register
- * @ptr32: register address
- */
-u32 dimcb_io_read(u32 __iomem *ptr32)
-{
-       return readl(ptr32);
-}
-
-/**
- * dimcb_io_write - callback from HAL to write value to an I/O register
- * @ptr32: register address
- * @value: value to write
- */
-void dimcb_io_write(u32 __iomem *ptr32, u32 value)
-{
-       writel(value, ptr32);
-}
-
-/**
- * dimcb_on_error - callback from HAL to report miscommunication between
- * HDM and HAL
- * @error_id: Error ID
- * @error_message: Error message. Some text in a free format
- */
-void dimcb_on_error(u8 error_id, const char *error_message)
-{
-       pr_err("dimcb_on_error: error_id - %d, error_message - %s\n", error_id,
-              error_message);
-}
-
-/**
- * startup_dim - initialize the dim2 interface
- * @pdev: platform device
- *
- * Get the value of command line parameter "clock_speed" if given or use the
- * default value, enable the clock and PLL, and initialize the dim2 interface.
- */
-static int startup_dim(struct platform_device *pdev)
-{
-       struct dim2_hdm *dev = platform_get_drvdata(pdev);
-       struct dim2_platform_data *pdata = pdev->dev.platform_data;
-       u8 hal_ret;
-
-       dev->clk_speed = -1;
-
-       if (clock_speed) {
-               if (!strcmp(clock_speed, "256fs"))
-                       dev->clk_speed = CLK_256FS;
-               else if (!strcmp(clock_speed, "512fs"))
-                       dev->clk_speed = CLK_512FS;
-               else if (!strcmp(clock_speed, "1024fs"))
-                       dev->clk_speed = CLK_1024FS;
-               else if (!strcmp(clock_speed, "2048fs"))
-                       dev->clk_speed = CLK_2048FS;
-               else if (!strcmp(clock_speed, "3072fs"))
-                       dev->clk_speed = CLK_3072FS;
-               else if (!strcmp(clock_speed, "4096fs"))
-                       dev->clk_speed = CLK_4096FS;
-               else if (!strcmp(clock_speed, "6144fs"))
-                       dev->clk_speed = CLK_6144FS;
-               else if (!strcmp(clock_speed, "8192fs"))
-                       dev->clk_speed = CLK_8192FS;
-       }
-
-       if (dev->clk_speed == -1) {
-               pr_info("Bad or missing clock speed parameter, using default value: 3072fs\n");
-               dev->clk_speed = CLK_3072FS;
-       } else {
-               pr_info("Selected clock speed: %s\n", clock_speed);
-       }
-       if (pdata && pdata->init) {
-               int ret = pdata->init(pdata, dev->io_base, dev->clk_speed);
-
-               if (ret)
-                       return ret;
-       }
-
-       pr_info("sync: num of frames per sub-buffer: %u\n", fcnt);
-       hal_ret = dim_startup(dev->io_base, dev->clk_speed, fcnt);
-       if (hal_ret != DIM_NO_ERROR) {
-               pr_err("dim_startup failed: %d\n", hal_ret);
-               if (pdata && pdata->destroy)
-                       pdata->destroy(pdata);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-/**
- * try_start_dim_transfer - try to transfer a buffer on a channel
- * @hdm_ch: channel specific data
- *
- * Transfer a buffer from pending_list if the channel is ready
- */
-static int try_start_dim_transfer(struct hdm_channel *hdm_ch)
-{
-       u16 buf_size;
-       struct list_head *head = &hdm_ch->pending_list;
-       struct mbo *mbo;
-       unsigned long flags;
-       struct dim_ch_state_t st;
-
-       BUG_ON(!hdm_ch);
-       BUG_ON(!hdm_ch->is_initialized);
-
-       spin_lock_irqsave(&dim_lock, flags);
-       if (list_empty(head)) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               return -EAGAIN;
-       }
-
-       if (!dim_get_channel_state(&hdm_ch->ch, &st)->ready) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               return -EAGAIN;
-       }
-
-       mbo = list_first_entry(head, struct mbo, list);
-       buf_size = mbo->buffer_length;
-
-       if (dim_dbr_space(&hdm_ch->ch) < buf_size) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               return -EAGAIN;
-       }
-
-       BUG_ON(mbo->bus_address == 0);
-       if (!dim_enqueue_buffer(&hdm_ch->ch, mbo->bus_address, buf_size)) {
-               list_del(head->next);
-               spin_unlock_irqrestore(&dim_lock, flags);
-               mbo->processed_length = 0;
-               mbo->status = MBO_E_INVAL;
-               mbo->complete(mbo);
-               return -EFAULT;
-       }
-
-       list_move_tail(head->next, &hdm_ch->started_list);
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       return 0;
-}
-
-/**
- * deliver_netinfo_thread - thread to deliver network status to mostcore
- * @data: private data
- *
- * Wait for network status and deliver it to mostcore once it is received
- */
-static int deliver_netinfo_thread(void *data)
-{
-       struct dim2_hdm *dev = data;
-
-       while (!kthread_should_stop()) {
-               wait_event_interruptible(dev->netinfo_waitq,
-                                        dev->deliver_netinfo ||
-                                        kthread_should_stop());
-
-               if (dev->deliver_netinfo) {
-                       dev->deliver_netinfo--;
-                       if (dev->on_netinfo) {
-                               dev->on_netinfo(&dev->most_iface,
-                                               dev->link_state,
-                                               dev->mac_addrs);
-                       }
-               }
-       }
-
-       return 0;
-}
-
-/**
- * retrieve_netinfo - retrieve network status from received buffer
- * @dev: private data
- * @mbo: received MBO
- *
- * Parse the message in buffer and get node address, link state, MAC address.
- * Wake up a thread to deliver this status to mostcore
- */
-static void retrieve_netinfo(struct dim2_hdm *dev, struct mbo *mbo)
-{
-       u8 *data = mbo->virt_address;
-
-       pr_info("Node Address: 0x%03x\n", (u16)data[16] << 8 | data[17]);
-       dev->link_state = data[18];
-       pr_info("NIState: %d\n", dev->link_state);
-       memcpy(dev->mac_addrs, data + 19, 6);
-       dev->deliver_netinfo++;
-       wake_up_interruptible(&dev->netinfo_waitq);
-}
-
-/**
- * service_done_flag - handle completed buffers
- * @dev: private data
- * @ch_idx: channel index
- *
- * Return back the completed buffers to mostcore, using completion callback
- */
-static void service_done_flag(struct dim2_hdm *dev, int ch_idx)
-{
-       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
-       struct dim_ch_state_t st;
-       struct list_head *head;
-       struct mbo *mbo;
-       int done_buffers;
-       unsigned long flags;
-       u8 *data;
-
-       BUG_ON(!hdm_ch);
-       BUG_ON(!hdm_ch->is_initialized);
-
-       spin_lock_irqsave(&dim_lock, flags);
-
-       done_buffers = dim_get_channel_state(&hdm_ch->ch, &st)->done_buffers;
-       if (!done_buffers) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               return;
-       }
-
-       if (!dim_detach_buffers(&hdm_ch->ch, done_buffers)) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               return;
-       }
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       head = &hdm_ch->started_list;
-
-       while (done_buffers) {
-               spin_lock_irqsave(&dim_lock, flags);
-               if (list_empty(head)) {
-                       spin_unlock_irqrestore(&dim_lock, flags);
-                       pr_crit("hard error: started_mbo list is empty whereas DIM2 has sent buffers\n");
-                       break;
-               }
-
-               mbo = list_first_entry(head, struct mbo, list);
-               list_del(head->next);
-               spin_unlock_irqrestore(&dim_lock, flags);
-
-               data = mbo->virt_address;
-
-               if (hdm_ch->data_type == MOST_CH_ASYNC &&
-                   hdm_ch->direction == MOST_CH_RX &&
-                   PACKET_IS_NET_INFO(data)) {
-                       retrieve_netinfo(dev, mbo);
-
-                       spin_lock_irqsave(&dim_lock, flags);
-                       list_add_tail(&mbo->list, &hdm_ch->pending_list);
-                       spin_unlock_irqrestore(&dim_lock, flags);
-               } else {
-                       if (hdm_ch->data_type == MOST_CH_CONTROL ||
-                           hdm_ch->data_type == MOST_CH_ASYNC) {
-                               u32 const data_size =
-                                       (u32)data[0] * 256 + data[1] + 2;
-
-                               mbo->processed_length =
-                                       min_t(u32, data_size,
-                                             mbo->buffer_length);
-                       } else {
-                               mbo->processed_length = mbo->buffer_length;
-                       }
-                       mbo->status = MBO_SUCCESS;
-                       mbo->complete(mbo);
-               }
-
-               done_buffers--;
-       }
-}
-
-static struct dim_channel **get_active_channels(struct dim2_hdm *dev,
-                                               struct dim_channel **buffer)
-{
-       int idx = 0;
-       int ch_idx;
-
-       for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) {
-               if (dev->hch[ch_idx].is_initialized)
-                       buffer[idx++] = &dev->hch[ch_idx].ch;
-       }
-       buffer[idx++] = NULL;
-
-       return buffer;
-}
-
-static irqreturn_t dim2_mlb_isr(int irq, void *_dev)
-{
-       struct dim2_hdm *dev = _dev;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dim_lock, flags);
-       dim_service_mlb_int_irq();
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       if (dev->atx_idx >= 0 && dev->hch[dev->atx_idx].is_initialized)
-               while (!try_start_dim_transfer(dev->hch + dev->atx_idx))
-                       continue;
-
-       return IRQ_HANDLED;
-}
-
-/**
- * dim2_tasklet_fn - tasklet function
- * @data: private data
- *
- * Service each initialized channel, if needed
- */
-static void dim2_tasklet_fn(unsigned long data)
-{
-       struct dim2_hdm *dev = (struct dim2_hdm *)data;
-       unsigned long flags;
-       int ch_idx;
-
-       for (ch_idx = 0; ch_idx < DMA_CHANNELS; ch_idx++) {
-               if (!dev->hch[ch_idx].is_initialized)
-                       continue;
-
-               spin_lock_irqsave(&dim_lock, flags);
-               dim_service_channel(&dev->hch[ch_idx].ch);
-               spin_unlock_irqrestore(&dim_lock, flags);
-
-               service_done_flag(dev, ch_idx);
-               while (!try_start_dim_transfer(dev->hch + ch_idx))
-                       continue;
-       }
-}
-
-/**
- * dim2_ahb_isr - interrupt service routine
- * @irq: irq number
- * @_dev: private data
- *
- * Acknowledge the interrupt and schedule a tasklet to service channels.
- * Return IRQ_HANDLED.
- */
-static irqreturn_t dim2_ahb_isr(int irq, void *_dev)
-{
-       struct dim2_hdm *dev = _dev;
-       struct dim_channel *buffer[DMA_CHANNELS + 1];
-       unsigned long flags;
-
-       spin_lock_irqsave(&dim_lock, flags);
-       dim_service_ahb_int_irq(get_active_channels(dev, buffer));
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       dim2_tasklet.data = (unsigned long)dev;
-       tasklet_schedule(&dim2_tasklet);
-       return IRQ_HANDLED;
-}
-
-/**
- * complete_all_mbos - complete MBO's in a list
- * @head: list head
- *
- * Delete all the entries in list and return back MBO's to mostcore using
- * completion call back.
- */
-static void complete_all_mbos(struct list_head *head)
-{
-       unsigned long flags;
-       struct mbo *mbo;
-
-       for (;;) {
-               spin_lock_irqsave(&dim_lock, flags);
-               if (list_empty(head)) {
-                       spin_unlock_irqrestore(&dim_lock, flags);
-                       break;
-               }
-
-               mbo = list_first_entry(head, struct mbo, list);
-               list_del(head->next);
-               spin_unlock_irqrestore(&dim_lock, flags);
-
-               mbo->processed_length = 0;
-               mbo->status = MBO_E_CLOSE;
-               mbo->complete(mbo);
-       }
-}
-
-/**
- * configure_channel - initialize a channel
- * @iface: interface the channel belongs to
- * @channel: channel to be configured
- * @channel_config: structure that holds the configuration information
- *
- * Receives configuration information from mostcore and initialize
- * the corresponding channel. Return 0 on success, negative on failure.
- */
-static int configure_channel(struct most_interface *most_iface, int ch_idx,
-                            struct most_channel_config *ccfg)
-{
-       struct dim2_hdm *dev = iface_to_hdm(most_iface);
-       bool const is_tx = ccfg->direction == MOST_CH_TX;
-       u16 const sub_size = ccfg->subbuffer_size;
-       u16 const buf_size = ccfg->buffer_size;
-       u16 new_size;
-       unsigned long flags;
-       u8 hal_ret;
-       int const ch_addr = ch_idx * 2 + 2;
-       struct hdm_channel *const hdm_ch = dev->hch + ch_idx;
-
-       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
-
-       if (hdm_ch->is_initialized)
-               return -EPERM;
-
-       switch (ccfg->data_type) {
-       case MOST_CH_CONTROL:
-               new_size = dim_norm_ctrl_async_buffer_size(buf_size);
-               if (new_size == 0) {
-                       pr_err("%s: too small buffer size\n", hdm_ch->name);
-                       return -EINVAL;
-               }
-               ccfg->buffer_size = new_size;
-               if (new_size != buf_size)
-                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
-                               hdm_ch->name, buf_size, new_size);
-               spin_lock_irqsave(&dim_lock, flags);
-               hal_ret = dim_init_control(&hdm_ch->ch, is_tx, ch_addr,
-                                          is_tx ? new_size * 2 : new_size);
-               break;
-       case MOST_CH_ASYNC:
-               new_size = dim_norm_ctrl_async_buffer_size(buf_size);
-               if (new_size == 0) {
-                       pr_err("%s: too small buffer size\n", hdm_ch->name);
-                       return -EINVAL;
-               }
-               ccfg->buffer_size = new_size;
-               if (new_size != buf_size)
-                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
-                               hdm_ch->name, buf_size, new_size);
-               spin_lock_irqsave(&dim_lock, flags);
-               hal_ret = dim_init_async(&hdm_ch->ch, is_tx, ch_addr,
-                                        is_tx ? new_size * 2 : new_size);
-               break;
-       case MOST_CH_ISOC:
-               new_size = dim_norm_isoc_buffer_size(buf_size, sub_size);
-               if (new_size == 0) {
-                       pr_err("%s: invalid sub-buffer size or too small buffer size\n",
-                              hdm_ch->name);
-                       return -EINVAL;
-               }
-               ccfg->buffer_size = new_size;
-               if (new_size != buf_size)
-                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
-                               hdm_ch->name, buf_size, new_size);
-               spin_lock_irqsave(&dim_lock, flags);
-               hal_ret = dim_init_isoc(&hdm_ch->ch, is_tx, ch_addr, sub_size);
-               break;
-       case MOST_CH_SYNC:
-               new_size = dim_norm_sync_buffer_size(buf_size, sub_size);
-               if (new_size == 0) {
-                       pr_err("%s: invalid sub-buffer size or too small buffer size\n",
-                              hdm_ch->name);
-                       return -EINVAL;
-               }
-               ccfg->buffer_size = new_size;
-               if (new_size != buf_size)
-                       pr_warn("%s: fixed buffer size (%d -> %d)\n",
-                               hdm_ch->name, buf_size, new_size);
-               spin_lock_irqsave(&dim_lock, flags);
-               hal_ret = dim_init_sync(&hdm_ch->ch, is_tx, ch_addr, sub_size);
-               break;
-       default:
-               pr_err("%s: configure failed, bad channel type: %d\n",
-                      hdm_ch->name, ccfg->data_type);
-               return -EINVAL;
-       }
-
-       if (hal_ret != DIM_NO_ERROR) {
-               spin_unlock_irqrestore(&dim_lock, flags);
-               pr_err("%s: configure failed (%d), type: %d, is_tx: %d\n",
-                      hdm_ch->name, hal_ret, ccfg->data_type, (int)is_tx);
-               return -ENODEV;
-       }
-
-       hdm_ch->data_type = ccfg->data_type;
-       hdm_ch->direction = ccfg->direction;
-       hdm_ch->is_initialized = true;
-
-       if (hdm_ch->data_type == MOST_CH_ASYNC &&
-           hdm_ch->direction == MOST_CH_TX &&
-           dev->atx_idx < 0)
-               dev->atx_idx = ch_idx;
-
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       return 0;
-}
-
-/**
- * enqueue - enqueue a buffer for data transfer
- * @iface: intended interface
- * @channel: ID of the channel the buffer is intended for
- * @mbo: pointer to the buffer object
- *
- * Push the buffer into pending_list and try to transfer one buffer from
- * pending_list. Return 0 on success, negative on failure.
- */
-static int enqueue(struct most_interface *most_iface, int ch_idx,
-                  struct mbo *mbo)
-{
-       struct dim2_hdm *dev = iface_to_hdm(most_iface);
-       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
-       unsigned long flags;
-
-       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
-
-       if (!hdm_ch->is_initialized)
-               return -EPERM;
-
-       if (mbo->bus_address == 0)
-               return -EFAULT;
-
-       spin_lock_irqsave(&dim_lock, flags);
-       list_add_tail(&mbo->list, &hdm_ch->pending_list);
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       (void)try_start_dim_transfer(hdm_ch);
-
-       return 0;
-}
-
-/**
- * request_netinfo - triggers retrieving of network info
- * @iface: pointer to the interface
- * @channel_id: corresponding channel ID
- *
- * Send a command to INIC which triggers retrieving of network info by means of
- * "Message exchange over MDP/MEP". Return 0 on success, negative on failure.
- */
-static void request_netinfo(struct most_interface *most_iface, int ch_idx,
-                           void (*on_netinfo)(struct most_interface *,
-                                              unsigned char, unsigned char *))
-{
-       struct dim2_hdm *dev = iface_to_hdm(most_iface);
-       struct mbo *mbo;
-       u8 *data;
-
-       dev->on_netinfo = on_netinfo;
-       if (!on_netinfo)
-               return;
-
-       if (dev->atx_idx < 0) {
-               pr_err("Async Tx Not initialized\n");
-               return;
-       }
-
-       mbo = most_get_mbo(&dev->most_iface, dev->atx_idx, NULL);
-       if (!mbo)
-               return;
-
-       mbo->buffer_length = 5;
-
-       data = mbo->virt_address;
-
-       data[0] = 0x00; /* PML High byte */
-       data[1] = 0x03; /* PML Low byte */
-       data[2] = 0x02; /* PMHL */
-       data[3] = 0x08; /* FPH */
-       data[4] = 0x40; /* FMF (FIFO cmd msg - Triggers NAOverMDP) */
-
-       most_submit_mbo(mbo);
-}
-
-/**
- * poison_channel - poison buffers of a channel
- * @iface: pointer to the interface the channel to be poisoned belongs to
- * @channel_id: corresponding channel ID
- *
- * Destroy a channel and complete all the buffers in both started_list &
- * pending_list. Return 0 on success, negative on failure.
- */
-static int poison_channel(struct most_interface *most_iface, int ch_idx)
-{
-       struct dim2_hdm *dev = iface_to_hdm(most_iface);
-       struct hdm_channel *hdm_ch = dev->hch + ch_idx;
-       unsigned long flags;
-       u8 hal_ret;
-       int ret = 0;
-
-       BUG_ON(ch_idx < 0 || ch_idx >= DMA_CHANNELS);
-
-       if (!hdm_ch->is_initialized)
-               return -EPERM;
-
-       tasklet_disable(&dim2_tasklet);
-       spin_lock_irqsave(&dim_lock, flags);
-       hal_ret = dim_destroy_channel(&hdm_ch->ch);
-       hdm_ch->is_initialized = false;
-       if (ch_idx == dev->atx_idx)
-               dev->atx_idx = -1;
-       spin_unlock_irqrestore(&dim_lock, flags);
-       tasklet_enable(&dim2_tasklet);
-       if (hal_ret != DIM_NO_ERROR) {
-               pr_err("HAL Failed to close channel %s\n", hdm_ch->name);
-               ret = -EFAULT;
-       }
-
-       complete_all_mbos(&hdm_ch->started_list);
-       complete_all_mbos(&hdm_ch->pending_list);
-
-       return ret;
-}
-
-/*
- * dim2_probe - dim2 probe handler
- * @pdev: platform device structure
- *
- * Register the dim2 interface with mostcore and initialize it.
- * Return 0 on success, negative on failure.
- */
-static int dim2_probe(struct platform_device *pdev)
-{
-       struct dim2_hdm *dev;
-       struct resource *res;
-       int ret, i;
-       struct kobject *kobj;
-       int irq;
-
-       dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-       if (!dev)
-               return -ENOMEM;
-
-       dev->atx_idx = -1;
-
-       platform_set_drvdata(pdev, dev);
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       dev->io_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dev->io_base))
-               return PTR_ERR(dev->io_base);
-
-       irq = platform_get_irq(pdev, 0);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get ahb0_int irq: %d\n", irq);
-               return irq;
-       }
-
-       ret = devm_request_irq(&pdev->dev, irq, dim2_ahb_isr, 0,
-                              "dim2_ahb0_int", dev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request ahb0_int irq %d\n", irq);
-               return ret;
-       }
-
-       irq = platform_get_irq(pdev, 1);
-       if (irq < 0) {
-               dev_err(&pdev->dev, "failed to get mlb_int irq: %d\n", irq);
-               return irq;
-       }
-
-       ret = devm_request_irq(&pdev->dev, irq, dim2_mlb_isr, 0,
-                              "dim2_mlb_int", dev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request mlb_int irq %d\n", irq);
-               return ret;
-       }
-
-       init_waitqueue_head(&dev->netinfo_waitq);
-       dev->deliver_netinfo = 0;
-       dev->netinfo_task = kthread_run(&deliver_netinfo_thread, (void *)dev,
-                                       "dim2_netinfo");
-       if (IS_ERR(dev->netinfo_task))
-               return PTR_ERR(dev->netinfo_task);
-
-       for (i = 0; i < DMA_CHANNELS; i++) {
-               struct most_channel_capability *cap = dev->capabilities + i;
-               struct hdm_channel *hdm_ch = dev->hch + i;
-
-               INIT_LIST_HEAD(&hdm_ch->pending_list);
-               INIT_LIST_HEAD(&hdm_ch->started_list);
-               hdm_ch->is_initialized = false;
-               snprintf(hdm_ch->name, sizeof(hdm_ch->name), "ca%d", i * 2 + 2);
-
-               cap->name_suffix = hdm_ch->name;
-               cap->direction = MOST_CH_RX | MOST_CH_TX;
-               cap->data_type = MOST_CH_CONTROL | MOST_CH_ASYNC |
-                                MOST_CH_ISOC | MOST_CH_SYNC;
-               cap->num_buffers_packet = MAX_BUFFERS_PACKET;
-               cap->buffer_size_packet = MAX_BUF_SIZE_PACKET;
-               cap->num_buffers_streaming = MAX_BUFFERS_STREAMING;
-               cap->buffer_size_streaming = MAX_BUF_SIZE_STREAMING;
-       }
-
-       {
-               const char *fmt;
-
-               if (sizeof(res->start) == sizeof(long long))
-                       fmt = "dim2-%016llx";
-               else if (sizeof(res->start) == sizeof(long))
-                       fmt = "dim2-%016lx";
-               else
-                       fmt = "dim2-%016x";
-
-               snprintf(dev->name, sizeof(dev->name), fmt, res->start);
-       }
-
-       dev->most_iface.interface = ITYPE_MEDIALB_DIM2;
-       dev->most_iface.description = dev->name;
-       dev->most_iface.num_channels = DMA_CHANNELS;
-       dev->most_iface.channel_vector = dev->capabilities;
-       dev->most_iface.configure = configure_channel;
-       dev->most_iface.enqueue = enqueue;
-       dev->most_iface.poison_channel = poison_channel;
-       dev->most_iface.request_netinfo = request_netinfo;
-
-       kobj = most_register_interface(&dev->most_iface);
-       if (IS_ERR(kobj)) {
-               ret = PTR_ERR(kobj);
-               dev_err(&pdev->dev, "failed to register MOST interface\n");
-               goto err_stop_thread;
-       }
-
-       ret = dim2_sysfs_probe(&dev->bus, kobj);
-       if (ret)
-               goto err_unreg_iface;
-
-       ret = startup_dim(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to initialize DIM2\n");
-               goto err_destroy_bus;
-       }
-
-       return 0;
-
-err_destroy_bus:
-       dim2_sysfs_destroy(&dev->bus);
-err_unreg_iface:
-       most_deregister_interface(&dev->most_iface);
-err_stop_thread:
-       kthread_stop(dev->netinfo_task);
-
-       return ret;
-}
-
-/**
- * dim2_remove - dim2 remove handler
- * @pdev: platform device structure
- *
- * Unregister the interface from mostcore
- */
-static int dim2_remove(struct platform_device *pdev)
-{
-       struct dim2_hdm *dev = platform_get_drvdata(pdev);
-       struct dim2_platform_data *pdata = pdev->dev.platform_data;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dim_lock, flags);
-       dim_shutdown();
-       spin_unlock_irqrestore(&dim_lock, flags);
-
-       if (pdata && pdata->destroy)
-               pdata->destroy(pdata);
-
-       dim2_sysfs_destroy(&dev->bus);
-       most_deregister_interface(&dev->most_iface);
-       kthread_stop(dev->netinfo_task);
-
-       /*
-        * break link to local platform_device_id struct
-        * to prevent crash by unload platform device module
-        */
-       pdev->id_entry = NULL;
-
-       return 0;
-}
-
-static const struct platform_device_id dim2_id[] = {
-       { "medialb_dim2" },
-       { }, /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(platform, dim2_id);
-
-static struct platform_driver dim2_driver = {
-       .probe = dim2_probe,
-       .remove = dim2_remove,
-       .id_table = dim2_id,
-       .driver = {
-               .name = "hdm_dim2",
-       },
-};
-
-module_platform_driver(dim2_driver);
-
-MODULE_AUTHOR("Jain Roy Ambi <JainRoy.Ambi@microchip.com>");
-MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
-MODULE_DESCRIPTION("MediaLB DIM2 Hardware Dependent Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/most/hdm-dim2/dim2_hdm.h b/drivers/staging/most/hdm-dim2/dim2_hdm.h
deleted file mode 100644 (file)
index 5f380b6..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_hdm.h - MediaLB DIM2 HDM Header
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#ifndef DIM2_HDM_H
-#define        DIM2_HDM_H
-
-struct device;
-
-/* platform dependent data for dim2 interface */
-struct dim2_platform_data {
-       int (*init)(struct dim2_platform_data *pd, void __iomem *io_base,
-                   int clk_speed);
-       void (*destroy)(struct dim2_platform_data *pd);
-       void *priv;
-};
-
-#endif /* DIM2_HDM_H */
diff --git a/drivers/staging/most/hdm-dim2/dim2_reg.h b/drivers/staging/most/hdm-dim2/dim2_reg.h
deleted file mode 100644 (file)
index 2b2fca4..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_reg.h - Definitions for registers of DIM2
- * (MediaLB, Device Interface Macro IP, OS62420)
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-#ifndef DIM2_OS62420_H
-#define        DIM2_OS62420_H
-
-#include <linux/types.h>
-
-struct dim2_regs {
-       /* 0x00 */ u32 MLBC0;
-       /* 0x01 */ u32 rsvd0[1];
-       /* 0x02 */ u32 MLBPC0;
-       /* 0x03 */ u32 MS0;
-       /* 0x04 */ u32 rsvd1[1];
-       /* 0x05 */ u32 MS1;
-       /* 0x06 */ u32 rsvd2[2];
-       /* 0x08 */ u32 MSS;
-       /* 0x09 */ u32 MSD;
-       /* 0x0A */ u32 rsvd3[1];
-       /* 0x0B */ u32 MIEN;
-       /* 0x0C */ u32 rsvd4[1];
-       /* 0x0D */ u32 MLBPC2;
-       /* 0x0E */ u32 MLBPC1;
-       /* 0x0F */ u32 MLBC1;
-       /* 0x10 */ u32 rsvd5[0x10];
-       /* 0x20 */ u32 HCTL;
-       /* 0x21 */ u32 rsvd6[1];
-       /* 0x22 */ u32 HCMR0;
-       /* 0x23 */ u32 HCMR1;
-       /* 0x24 */ u32 HCER0;
-       /* 0x25 */ u32 HCER1;
-       /* 0x26 */ u32 HCBR0;
-       /* 0x27 */ u32 HCBR1;
-       /* 0x28 */ u32 rsvd7[8];
-       /* 0x30 */ u32 MDAT0;
-       /* 0x31 */ u32 MDAT1;
-       /* 0x32 */ u32 MDAT2;
-       /* 0x33 */ u32 MDAT3;
-       /* 0x34 */ u32 MDWE0;
-       /* 0x35 */ u32 MDWE1;
-       /* 0x36 */ u32 MDWE2;
-       /* 0x37 */ u32 MDWE3;
-       /* 0x38 */ u32 MCTL;
-       /* 0x39 */ u32 MADR;
-       /* 0x3A */ u32 rsvd8[0xB6];
-       /* 0xF0 */ u32 ACTL;
-       /* 0xF1 */ u32 rsvd9[3];
-       /* 0xF4 */ u32 ACSR0;
-       /* 0xF5 */ u32 ACSR1;
-       /* 0xF6 */ u32 ACMR0;
-       /* 0xF7 */ u32 ACMR1;
-};
-
-#define DIM2_MASK(n)  (~((~(u32)0) << (n)))
-
-enum {
-       MLBC0_MLBLK_BIT = 7,
-
-       MLBC0_MLBPEN_BIT = 5,
-
-       MLBC0_MLBCLK_SHIFT = 2,
-       MLBC0_MLBCLK_VAL_256FS = 0,
-       MLBC0_MLBCLK_VAL_512FS = 1,
-       MLBC0_MLBCLK_VAL_1024FS = 2,
-       MLBC0_MLBCLK_VAL_2048FS = 3,
-
-       MLBC0_FCNT_SHIFT = 15,
-       MLBC0_FCNT_MASK = 7,
-       MLBC0_FCNT_MAX_VAL = 6,
-
-       MLBC0_MLBEN_BIT = 0,
-
-       MIEN_CTX_BREAK_BIT = 29,
-       MIEN_CTX_PE_BIT = 28,
-       MIEN_CTX_DONE_BIT = 27,
-
-       MIEN_CRX_BREAK_BIT = 26,
-       MIEN_CRX_PE_BIT = 25,
-       MIEN_CRX_DONE_BIT = 24,
-
-       MIEN_ATX_BREAK_BIT = 22,
-       MIEN_ATX_PE_BIT = 21,
-       MIEN_ATX_DONE_BIT = 20,
-
-       MIEN_ARX_BREAK_BIT = 19,
-       MIEN_ARX_PE_BIT = 18,
-       MIEN_ARX_DONE_BIT = 17,
-
-       MIEN_SYNC_PE_BIT = 16,
-
-       MIEN_ISOC_BUFO_BIT = 1,
-       MIEN_ISOC_PE_BIT = 0,
-
-       MLBC1_NDA_SHIFT = 8,
-       MLBC1_NDA_MASK = 0xFF,
-
-       MLBC1_CLKMERR_BIT = 7,
-       MLBC1_LOCKERR_BIT = 6,
-
-       ACTL_DMA_MODE_BIT = 2,
-       ACTL_DMA_MODE_VAL_DMA_MODE_0 = 0,
-       ACTL_DMA_MODE_VAL_DMA_MODE_1 = 1,
-       ACTL_SCE_BIT = 0,
-
-       HCTL_EN_BIT = 15
-};
-
-enum {
-       CDT0_RPC_SHIFT = 16 + 11,
-       CDT0_RPC_MASK = DIM2_MASK(5),
-
-       CDT1_BS_ISOC_SHIFT = 0,
-       CDT1_BS_ISOC_MASK = DIM2_MASK(9),
-
-       CDT3_BD_SHIFT = 0,
-       CDT3_BD_MASK = DIM2_MASK(12),
-       CDT3_BD_ISOC_MASK = DIM2_MASK(13),
-       CDT3_BA_SHIFT = 16,
-
-       ADT0_CE_BIT = 15,
-       ADT0_LE_BIT = 14,
-       ADT0_PG_BIT = 13,
-
-       ADT1_RDY_BIT = 15,
-       ADT1_DNE_BIT = 14,
-       ADT1_ERR_BIT = 13,
-       ADT1_PS_BIT = 12,
-       ADT1_MEP_BIT = 11,
-       ADT1_BD_SHIFT = 0,
-       ADT1_CTRL_ASYNC_BD_MASK = DIM2_MASK(11),
-       ADT1_ISOC_SYNC_BD_MASK = DIM2_MASK(13),
-
-       CAT_FCE_BIT = 14,
-       CAT_MFE_BIT = 14,
-
-       CAT_MT_BIT = 13,
-
-       CAT_RNW_BIT = 12,
-
-       CAT_CE_BIT = 11,
-
-       CAT_CT_SHIFT = 8,
-       CAT_CT_VAL_SYNC = 0,
-       CAT_CT_VAL_CONTROL = 1,
-       CAT_CT_VAL_ASYNC = 2,
-       CAT_CT_VAL_ISOC = 3,
-
-       CAT_CL_SHIFT = 0,
-       CAT_CL_MASK = DIM2_MASK(6)
-};
-
-#endif /* DIM2_OS62420_H */
diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.c b/drivers/staging/most/hdm-dim2/dim2_sysfs.c
deleted file mode 100644 (file)
index 3a2ad35..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_sysfs.c - MediaLB sysfs information
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/kernel.h>
-#include "dim2_sysfs.h"
-
-struct bus_attr {
-       struct attribute attr;
-       ssize_t (*show)(struct medialb_bus *bus, char *buf);
-       ssize_t (*store)(struct medialb_bus *bus, const char *buf,
-                        size_t count);
-};
-
-static ssize_t state_show(struct medialb_bus *bus, char *buf)
-{
-       bool state = dim2_sysfs_get_state_cb();
-
-       return sprintf(buf, "%s\n", state ? "locked" : "");
-}
-
-static struct bus_attr state_attr = __ATTR_RO(state);
-
-static struct attribute *bus_default_attrs[] = {
-       &state_attr.attr,
-       NULL,
-};
-
-static const struct attribute_group bus_attr_group = {
-       .attrs = bus_default_attrs,
-};
-
-static void bus_kobj_release(struct kobject *kobj)
-{
-}
-
-static ssize_t bus_kobj_attr_show(struct kobject *kobj, struct attribute *attr,
-                                 char *buf)
-{
-       struct medialb_bus *bus =
-               container_of(kobj, struct medialb_bus, kobj_group);
-       struct bus_attr *xattr = container_of(attr, struct bus_attr, attr);
-
-       if (!xattr->show)
-               return -EIO;
-
-       return xattr->show(bus, buf);
-}
-
-static ssize_t bus_kobj_attr_store(struct kobject *kobj, struct attribute *attr,
-                                  const char *buf, size_t count)
-{
-       struct medialb_bus *bus =
-               container_of(kobj, struct medialb_bus, kobj_group);
-       struct bus_attr *xattr = container_of(attr, struct bus_attr, attr);
-
-       if (!xattr->store)
-               return -EIO;
-
-       return xattr->store(bus, buf, count);
-}
-
-static struct sysfs_ops const bus_kobj_sysfs_ops = {
-       .show = bus_kobj_attr_show,
-       .store = bus_kobj_attr_store,
-};
-
-static struct kobj_type bus_ktype = {
-       .release = bus_kobj_release,
-       .sysfs_ops = &bus_kobj_sysfs_ops,
-};
-
-int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj)
-{
-       int err;
-
-       kobject_init(&bus->kobj_group, &bus_ktype);
-       err = kobject_add(&bus->kobj_group, parent_kobj, "bus");
-       if (err) {
-               pr_err("kobject_add() failed: %d\n", err);
-               goto err_kobject_add;
-       }
-
-       err = sysfs_create_group(&bus->kobj_group, &bus_attr_group);
-       if (err) {
-               pr_err("sysfs_create_group() failed: %d\n", err);
-               goto err_create_group;
-       }
-
-       return 0;
-
-err_create_group:
-       kobject_put(&bus->kobj_group);
-
-err_kobject_add:
-       return err;
-}
-
-void dim2_sysfs_destroy(struct medialb_bus *bus)
-{
-       kobject_put(&bus->kobj_group);
-}
diff --git a/drivers/staging/most/hdm-dim2/dim2_sysfs.h b/drivers/staging/most/hdm-dim2/dim2_sysfs.h
deleted file mode 100644 (file)
index e46dc4b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * dim2_sysfs.h - MediaLB sysfs information
- *
- * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
- */
-
-/* Author: Andrey Shvetsov <andrey.shvetsov@k2l.de> */
-
-#ifndef DIM2_SYSFS_H
-#define        DIM2_SYSFS_H
-
-#include <linux/kobject.h>
-
-struct medialb_bus {
-       struct kobject kobj_group;
-};
-
-struct dim2_hdm;
-
-int dim2_sysfs_probe(struct medialb_bus *bus, struct kobject *parent_kobj);
-void dim2_sysfs_destroy(struct medialb_bus *bus);
-
-/*
- * callback,
- * must deliver MediaLB state as true if locked or false if unlocked
- */
-bool dim2_sysfs_get_state_cb(void);
-
-#endif /* DIM2_SYSFS_H */