1
0
Fork 0

MLK-23394-2: XUVI/PPM: driver initial version.

Initial version of XUVI/PPM driver source code. The driver is based
on DVB core. It will work with XUVI/PPM FW to provide TS stream
filtering and demux.

Signed-off-by: Bing Song <bing.song@nxp.com>
Reviewed-by: Jian Li <jian.li@nxp.com>
Reviewed-by: Zhou Peng <eagle.zhou@nxp.com>
5.4-rM2-2.2.x-imx-squashed
Bing Song 2018-12-10 10:57:57 -08:00
parent 92490d1837
commit dd1846596f
8 changed files with 1765 additions and 0 deletions

View File

@ -0,0 +1,14 @@
#
# DVB device configuration
#
menu "XUVI/PPM HW TS filter and demux"
depends on ARCH_MXC
config MXC_IMX_DMX_HW
tristate "Enable HW Implementation based on XUVI/PPM"
default y
help
Hardware demux driver implementation using PPM
endmenu

View File

@ -0,0 +1,3 @@
obj-$(CONFIG_MXC_IMX_DMX_HW) += xuvi_pm.o
obj-$(CONFIG_MXC_IMX_DMX_HW) += xuvi_mu.o
obj-$(CONFIG_MXC_IMX_DMX_HW) += ppm.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,183 @@
/*
* Copyright 2019-2020 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*!
* @file ppm.h
*
* copyright here may be changed later
*
*
*/
#ifndef __PPM_H__
#define __PPM_H__
#include <linux/slab.h>
#include "media/demux.h"
#define CONFIG_PROC_FS 1
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>
#include <linux/wait.h>
#include <linux/mailbox_client.h>
#include "media/dvbdev.h"
#include "media/dmxdev.h"
#include "media/demux.h"
#include "media/dvb_demux.h"
#include "media/dvb_frontend.h"
#include "media/dvb_net.h"
#define VID_API_COMMAND_LIMIT 64
#define PPM_MESSAGE_LIMIT 256
#define MSG_WORD_LENGTH 3
#define PPM_MAX_INSTANCE 2
#define PPM_TS_188 0
#define PPM_TS_204 1
#define BUF_NUM 36
#define BUF_SIZE (1*1024*1024)
#define LOG_OFFSET (2*1024*1024)
#define MSG_SIZE 4
#define MU_CHANNEL 8
#define PPM_WATCHDOG_INTERVAL_MS 1000
#define M0FW_FILENAME "imx/xuvi/vpu_fw_imx8_xuvi.bin"
enum {
INIT_DONE = 1,
RPC_BUF_OFFSET,
/*PRINT_BUF_OFFSET, */
BOOT_ADDRESS,
COMMAND,
EVENT,
BUF_TO = 16,
BUF_FROM,
ADD_PID,
RM_PID,
STOP,
HARD_FAULT,
DRAIN_DONE,
FLUSH_DONE,
SNAP_SHOT
};
struct event_msg {
u32 idx;
u32 msgnum;
u32 msgid;
u32 msgdata[MSG_SIZE];
};
struct ppm_buf_list {
struct list_head list;
void *vir;
u32 phy;
u32 size;
};
struct print_buf_desc {
u32 start_h_phy;
u32 start_h_vir;
u32 start_m;
u32 bytes;
u32 read;
u32 write;
char buffer[0];
};
struct xuvi_mu_chan {
struct ppm_dev *dev;
int idx;
struct mbox_client cl;
struct mbox_chan *ch;
};
struct ppm_ctx;
struct ppm_dev {
struct device *generic_dev;
struct video_device *pppm_decoder_dev;
struct platform_device *plat_dev;
struct firmware *pfw;
void *fw_space_vir;
u32 fw_space_phy;
u32 boot_size;
struct mutex dev_mutex;
struct mutex dev_ins_mutex;
struct mutex cmd_mutex;
bool fw_is_ready;
bool fw_started;
struct completion fw_start_comp;
struct completion snap_done_comp;
struct delayed_work watchdog;
struct workqueue_struct *workqueue;
struct work_struct msg_work;
struct clk *ppm_clk;
struct ppm_buf_list bufs[BUF_NUM];
struct list_head buf_list;
struct mutex buf_list_lock;
struct ppm_buf_list out_bufs[BUF_NUM];
struct kfifo msg_fifo;
struct print_buf_desc *print_buf;
void __iomem *regs_base;
void __iomem *csr_base;
struct wait_queue_head buffer_wq;
struct ppm_ctx *ctx[PPM_MAX_INSTANCE];
bool suspend;
struct xuvi_mu_chan mu_chans[MU_CHANNEL];
struct device *pd_vpu;
struct device *pd_ts;
struct device *pd_mu;
struct device_link *pd_vpu_link;
struct device_link *pd_ts_link;
struct device_link *pd_mu_link;
};
struct ppm_ctx {
struct ppm_dev *dev;
/* DVB stuff */
struct dvb_adapter dvb_adapter;
struct dvb_frontend *fe;
struct dvb_demux demux;
struct dmxdev dmxdev;
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
struct dvb_net dvbnet;
int idx;
struct kfifo msg_fifo;
struct mutex instance_mutex;
struct work_struct instance_work;
struct workqueue_struct *instance_wq;
struct completion stop_comp;
struct completion eos_comp;
bool start_flag;
bool wait_abort_done;
bool wait_rst_done;
bool fw_stopped;
bool stop_start;
bool fw_finished;
bool eos_stop_received;
bool eos_stop_added;
bool ctx_released;
bool hang_status;
bool instance_activated;
u8 feeds;
};
#endif // __PPM_H__ //

View File

@ -0,0 +1,111 @@
/*
* Copyright 2020 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
*
* @file xuvi_mu.c
*
*/
#include "xuvi_mu.h"
static void xuvi_rx_callback(struct mbox_client *c, void *msg)
{
struct xuvi_mu_chan *mu_chan =
container_of(c, struct xuvi_mu_chan, cl);
struct ppm_dev *dev = mu_chan->dev;
static uint32_t msg_mu[4], msg_mask;
u32 *data = msg;
msg_mu[mu_chan->idx] = *data;
msg_mask |= 1 << mu_chan->idx;
if (msg_mask == 0xF) {
msg_mask = 0;
if (kfifo_in(&dev->msg_fifo, msg_mu, sizeof(uint32_t) * 4)
!= sizeof(uint32_t) * 4) {
return;
}
queue_work(dev->workqueue, &dev->msg_work);
}
}
int xuvi_mu_request(struct ppm_dev *dev)
{
struct xuvi_mu_chan *mu_chan;
struct mbox_client *cl;
char *chan_name;
int ret = 0;
int i;
for (i = 0; i < MU_CHANNEL; i++) {
if (i < 4)
chan_name = kasprintf(GFP_KERNEL, "ts_tx%d", i);
else
chan_name =
kasprintf(GFP_KERNEL, "ts_rx%d", i - 4);
if (!chan_name)
return -ENOMEM;
mu_chan = &dev->mu_chans[i];
cl = &mu_chan->cl;
cl->dev = &dev->plat_dev->dev;
if (i == 1 || i == 2 || i == 3) {
cl->tx_block = false;
} else {
cl->tx_block = true;
cl->tx_tout = 1000;
}
cl->knows_txdone = false;
cl->rx_callback = xuvi_rx_callback;
mu_chan->dev = dev;
mu_chan->idx = i % 4;
mu_chan->ch = mbox_request_channel_byname(cl, chan_name);
if (IS_ERR(mu_chan->ch)) {
ret = PTR_ERR(mu_chan->ch);
if (ret != -EPROBE_DEFER)
printk
("Failed to request mbox chan %s ret %d\n",
chan_name, ret);
kfree(chan_name);
return ret;
}
kfree(chan_name);
}
return ret;
}
void xuvi_mu_free(struct ppm_dev *dev)
{
int i;
for (i = 0; i < MU_CHANNEL; i++) {
if (dev->mu_chans[i].ch && !IS_ERR(dev->mu_chans[i].ch))
mbox_free_channel(dev->mu_chans[i].ch);
dev->mu_chans[i].ch = NULL;
}
}
void xuvi_mu_send_msg(struct ppm_dev *dev, uint32_t value0,
uint32_t value1, uint32_t value2, uint32_t value3)
{
mbox_send_message(dev->mu_chans[3].ch, &value3);
mbox_send_message(dev->mu_chans[2].ch, &value2);
mbox_send_message(dev->mu_chans[1].ch, &value1);
mbox_send_message(dev->mu_chans[0].ch, &value0);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2020 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
*
* @file xuvi_mu.h
*
*/
#ifndef _XUVI_MU_H_
#define _XUVI_MU_H_
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/mx8_mu.h>
#include <linux/workqueue.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/mailbox_client.h>
#include <linux/pm_domain.h>
#include <linux/kfifo.h>
#include "ppm.h"
int xuvi_mu_request(struct ppm_dev *dev);
void xuvi_mu_free(struct ppm_dev *dev);
void xuvi_mu_send_msg(struct ppm_dev *dev, uint32_t value0,
uint32_t value1, uint32_t value2, uint32_t value3);
#endif

View File

@ -0,0 +1,112 @@
/*
* Copyright 2020 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
*
* @file xuvi_pm.c
*
*/
#include "xuvi_pm.h"
#define vpu_err printk
int xuvi_attach_pm_domains(struct ppm_dev *dev)
{
int ret = 0;
dev->pd_vpu =
dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpu");
if (IS_ERR(dev->pd_vpu)) {
vpu_err("error: %s unable to get vpu power domain\n",
__func__);
ret = PTR_ERR(dev->pd_vpu);
goto err;
}
dev->pd_vpu_link =
device_link_add(&dev->plat_dev->dev, dev->pd_vpu,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (IS_ERR(dev->pd_vpu_link)) {
vpu_err("error: %s unable to link vpu power domain\n",
__func__);
ret = PTR_ERR(dev->pd_vpu_link);
goto err;
}
dev->pd_ts =
dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vputs");
if (IS_ERR(dev->pd_ts)) {
vpu_err("error: %s unable to get vpu ts power domain\n",
__func__);
ret = PTR_ERR(dev->pd_ts);
goto err;
}
dev->pd_ts_link = device_link_add(&dev->plat_dev->dev, dev->pd_ts,
DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (IS_ERR(dev->pd_ts_link)) {
vpu_err("error: %s unable to link vpu ts power domain\n",
__func__);
ret = PTR_ERR(dev->pd_ts_link);
goto err;
}
dev->pd_mu =
dev_pm_domain_attach_by_name(&dev->plat_dev->dev, "vpumu3");
if (IS_ERR(dev->pd_mu)) {
vpu_err("error: %s unable to get vpu mu0 power domain\n",
__func__);
ret = PTR_ERR(dev->pd_mu);
goto err;
}
dev->pd_mu_link = device_link_add(&dev->plat_dev->dev, dev->pd_mu,
DL_FLAG_STATELESS |
DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
if (IS_ERR(dev->pd_mu_link)) {
vpu_err("error: %s unable to link vpu mu0 power domain\n",
__func__);
ret = PTR_ERR(dev->pd_mu_link);
goto err;
}
return ret;
err:
xuvi_detach_pm_domains(dev);
return ret;
}
void xuvi_detach_pm_domains(struct ppm_dev *dev)
{
if (dev->pd_vpu_link && !IS_ERR(dev->pd_vpu_link))
device_link_del(dev->pd_vpu_link);
if (dev->pd_vpu && !IS_ERR(dev->pd_vpu))
dev_pm_domain_detach(dev->pd_vpu, true);
if (dev->pd_ts_link && !IS_ERR(dev->pd_ts_link))
device_link_del(dev->pd_ts_link);
if (dev->pd_ts && !IS_ERR(dev->pd_ts))
dev_pm_domain_detach(dev->pd_ts, true);
if (dev->pd_mu_link && !IS_ERR(dev->pd_mu_link))
device_link_del(dev->pd_mu_link);
if (dev->pd_mu && !IS_ERR(dev->pd_mu))
dev_pm_domain_detach(dev->pd_mu, true);
dev->pd_vpu = NULL;
dev->pd_vpu_link = NULL;
dev->pd_ts = NULL;
dev->pd_ts_link = NULL;
dev->pd_mu = NULL;
dev->pd_mu_link = NULL;
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2020 NXP
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
*
* @file xuvi_pm.h
*
*/
#ifndef _XUVI_PM_H_
#define _XUVI_PM_H_
#include <linux/version.h>
#include <linux/pm_domain.h>
#include <linux/platform_device.h>
#include "ppm.h"
int xuvi_attach_pm_domains(struct ppm_dev *dev);
void xuvi_detach_pm_domains(struct ppm_dev *dev);
#endif