--- /dev/null
+#
+# Exynos tsmux device driver
+#
+
+config VIDEO_EXYNOS_TSMUX
+ bool "EXYNOS TSMUX Driver"
+ depends on VIDEO_EXYNOS
+ default n
+ ---help---
+ Repeater driver for WFD
--- /dev/null
+#
+# Copyright (c) 2016 Samsung Electronics Co., Ltd.
+# http://www.samsung.com
+#
+# Licensed under GPLv2
+#
+
+tsmux-objs := tsmux_dev.o tsmux_reg.o
+obj-$(CONFIG_VIDEO_EXYNOS_TSMUX) += tsmux.o
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Header file for Exynos TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef TSMUX_H
+#define TSMUX_H
+
+#define TSMUX_VIDEO_PID 0x1011
+#define TSMUX_AUDIO_PID 0x1100
+
+#define TSMUX_AVC_STREAM_TYPE 0x1b
+#define TSMUX_AVC_STREAM_ID 0xe0
+
+#define TSMUX_AAC_STREAM_TYPE 0x0f
+#define TSMUX_AAC_STREAM_ID 0xc0
+
+#define TSMUX_MAX_CMD_QUEUE_NUM 4
+#define TSMUX_MAX_M2M_CMD_QUEUE_NUM 3
+#define TSMUX_MAX_CONTEXTS_NUM 1
+#define TSMUX_OUT_BUF_CNT 4
+
+#define TSMUX_PSI_SIZE 64
+#define TSMUX_PES_HDR_SIZE 16
+#define TSMUX_TS_HDR_SIZE 4
+#define TSMUX_RTP_HDR_SIZE 8
+
+struct tsmux_pkt_ctrl {
+ int32_t psi_en;
+ int32_t rtp_size;
+ int32_t rtp_seq_override;
+ int32_t pes_stuffing_num;
+ int32_t mode;
+ int32_t id;
+};
+
+struct tsmux_pes_hdr {
+ int32_t code;
+ int32_t stream_id;
+ int32_t pkt_len;
+ int32_t marker;
+ int32_t scramble;
+ int32_t priority;
+ int32_t alignment;
+ int32_t copyright;
+ int32_t original;
+ int32_t flags;
+ int32_t hdr_len;
+ int32_t pts39_16;
+ int32_t pts15_0;
+};
+
+struct tsmux_ts_hdr {
+ int32_t sync;
+ int32_t error;
+ int32_t priority;
+ int32_t pid;
+ int32_t scramble;
+ int32_t adapt_ctrl;
+ int32_t continuity_counter;
+};
+
+struct tsmux_rtp_hdr {
+ int32_t ver;
+ int32_t pad;
+ int32_t ext;
+ int32_t csrc_cnt;
+ int32_t marker;
+ int32_t pl_type;
+ int32_t seq;
+ int32_t ssrc;
+};
+
+struct tsmux_swp_ctrl {
+ int32_t swap_ctrl_out4;
+ int32_t swap_ctrl_out1;
+ int32_t swap_ctrl_in4;
+ int32_t swap_ctrl_in1;
+};
+
+struct tsmux_hex_ctrl {
+ int32_t m2m_enable;
+ int32_t m2m_key[4];
+ int32_t m2m_cnt[4];
+ int32_t m2m_stream_cnt;
+ int32_t otf_enable;
+ int32_t otf_key[4];
+ int32_t otf_cnt[4];
+ int32_t otf_stream_cnt;
+ int32_t dbg_ctrl_bypass;
+};
+
+struct tsmux_psi_info {
+ int32_t psi_data[TSMUX_PSI_SIZE];
+ int32_t pcr_len;
+ int32_t pmt_len;
+ int32_t pat_len;
+};
+
+struct tsmux_buffer {
+ int32_t ion_buf_fd;
+ int32_t buffer_size;
+ int32_t offset;
+ int32_t actual_size;
+ int32_t es_size;
+ int32_t state;
+ int32_t job_done;
+ int32_t partial_done;
+ int64_t time_stamp;
+
+ int64_t g2d_start_stamp;
+ int64_t g2d_end_stamp;
+ int64_t mfc_start_stamp;
+ int64_t mfc_end_stamp;
+ int64_t tsmux_start_stamp;
+ int64_t tsmux_end_stamp;
+ int64_t kernel_end_stamp;
+};
+
+struct tsmux_job {
+ struct tsmux_pkt_ctrl pkt_ctrl;
+ struct tsmux_pes_hdr pes_hdr;
+ struct tsmux_ts_hdr ts_hdr;
+ struct tsmux_rtp_hdr rtp_hdr;
+ struct tsmux_swp_ctrl swp_ctrl;
+ struct tsmux_hex_ctrl hex_ctrl;
+ struct tsmux_buffer in_buf;
+ struct tsmux_buffer out_buf;
+};
+
+struct tsmux_otf_config {
+ struct tsmux_pkt_ctrl pkt_ctrl;
+ struct tsmux_pes_hdr pes_hdr;
+ struct tsmux_ts_hdr ts_hdr;
+ struct tsmux_rtp_hdr rtp_hdr;
+ struct tsmux_swp_ctrl swp_ctrl;
+ struct tsmux_hex_ctrl hex_ctrl;
+};
+
+struct tsmux_m2m_cmd_queue {
+ struct tsmux_job m2m_job[TSMUX_MAX_M2M_CMD_QUEUE_NUM];
+};
+
+struct tsmux_otf_cmd_queue {
+ // user read parameter
+ int32_t cur_buf_num;
+ struct tsmux_buffer out_buf[TSMUX_OUT_BUF_CNT];
+
+ // user write parameter
+ struct tsmux_otf_config config;
+};
+
+struct tsmux_rtp_ts_info {
+ int32_t rtp_seq_number;
+ int32_t rtp_seq_override;
+
+ int32_t ts_pat_cc;
+ int32_t ts_pmt_cc;
+
+ int32_t ts_video_cc;
+ int32_t ts_audio_cc;
+};
+
+#define TSMUX_IOCTL_SET_INFO \
+ _IOW('T', 0x1, struct tsmux_psi_info)
+
+#define TSMUX_IOCTL_M2M_MAP_BUF \
+ _IOWR('A', 0x10, struct tsmux_m2m_cmd_queue)
+#define TSMUX_IOCTL_M2M_UNMAP_BUF \
+ _IO('A', 0x11)
+#define TSMUX_IOCTL_M2M_RUN \
+ _IOWR('A', 0x12, struct tsmux_m2m_cmd_queue)
+
+#define TSMUX_IOCTL_OTF_MAP_BUF \
+ _IOR('A', 0x13, struct tsmux_otf_cmd_queue)
+#define TSMUX_IOCTL_OTF_UNMAP_BUF \
+ _IO('A', 0x14)
+#define TSMUX_IOCTL_OTF_DQ_BUF \
+ _IOR('A', 0x15, struct tsmux_otf_cmd_queue)
+#define TSMUX_IOCTL_OTF_Q_BUF \
+ _IOW('A', 0x16, int32_t)
+#define TSMUX_IOCTL_OTF_SET_CONFIG \
+ _IOW('A', 0x17, struct tsmux_otf_config)
+
+#define TSMUX_IOCTL_SET_RTP_TS_INFO \
+ _IOW('A', 0x20, struct tsmux_rtp_ts_info)
+#define TSMUX_IOCTL_GET_RTP_TS_INFO \
+ _IOW('A', 0x21, struct tsmux_rtp_ts_info)
+
+#endif /* TSMUX_H */
--- /dev/null
+/*
+ * copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef TSMUX_DBG_H
+#define TSMUX_DBG_H
+
+extern int g_tsmux_debug_level;
+
+#define TSMUX_DBG_SFR (1 << 5)
+#define TSMUX_SFR (1 << 4)
+#define TSMUX_OTF (1 << 3)
+#define TSMUX_M2M (1 << 2)
+#define TSMUX_COMMON (1 << 1)
+#define TSMUX_ERR (1)
+
+#define print_tsmux(level, fmt, args...) \
+ do { \
+ if ((g_tsmux_debug_level & level)) \
+ pr_info("%s:%d: " fmt, \
+ __func__, __LINE__, ##args); \
+ } while (0)
+#endif
--- /dev/null
+/*
+ * copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/pm_runtime.h>
+#include <linux/exynos_iovmm.h>
+
+#include "tsmux_dev.h"
+#include "tsmux_reg.h"
+#include "tsmux_dbg.h"
+
+#define MAX_JOB_DONE_WAIT_TIME 1000000
+#define AUDIO_TIME_PERIOD_US 21333
+#define ADD_NULL_TS_PACKET
+
+#define RTP_HEADER_SIZE 12
+#define TS_PACKET_SIZE 188
+
+static struct tsmux_device *g_tsmux_dev;
+int g_tsmux_debug_level;
+module_param(g_tsmux_debug_level, int, 0600);
+
+static inline int get_pes_len(int src_len, bool hdcp, bool audio)
+{
+ int pes_len = 0;
+
+ pes_len = src_len;
+ pes_len += 14;
+ if (hdcp)
+ pes_len += 17;
+ if (audio)
+ pes_len += 2;
+ return pes_len;
+}
+
+static inline int get_ts_len(int pes_len, bool psi)
+{
+ int ts_len = 0;
+
+ if (psi)
+ ts_len += 3 * 188;
+ ts_len += (pes_len + 183) / 184 * 188;
+ return ts_len;
+}
+
+static inline int get_rtp_len(int ts_len, int num_ts_per_rtp)
+{
+ int rtp_len = 0;
+
+ rtp_len = (ts_len / (num_ts_per_rtp * 188) + 1) * 12 + ts_len;
+ return rtp_len;
+}
+
+static inline int get_m2m_buffer_idx(int job_id)
+{
+ return job_id - 1;
+}
+
+static inline int get_m2m_job_id(int buffer_idx)
+{
+ return buffer_idx + 1;
+}
+
+static inline bool is_m2m_job_done(struct tsmux_context *ctx)
+{
+ int i;
+ bool ret = true;
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ if (ctx->m2m_job_done[i] == false)
+ ret = false;
+ }
+
+ return ret;
+}
+
+static inline bool is_otf_job_done(struct tsmux_context *ctx)
+{
+ int i;
+ bool ret = false;
+ struct tsmux_device *tsmux_dev = ctx->tsmux_dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ if (ctx->otf_outbuf_info[i].buf_state == BUF_DONE) {
+ ret = true;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ return ret;
+}
+
+static inline bool is_audio(u32 stream_type)
+{
+ bool is_audio = false;
+
+ if (stream_type == TSMUX_AAC_STREAM_TYPE)
+ is_audio = true;
+
+ return is_audio;
+}
+
+static int tsmux_iommu_fault_handler(
+ struct iommu_domain *domain, struct device *dev,
+ unsigned long fault_addr, int fault_flags, void *token)
+{
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return 0;
+}
+
+static int increment_ts_continuity_counter(
+ int ts_continuity_counter, int rtp_size,
+ int ts_packet_count_in_rtp, bool psi_enable)
+{
+ int rtp_packet_count = rtp_size / (TS_PACKET_SIZE * ts_packet_count_in_rtp + RTP_HEADER_SIZE);
+ int ts_packet_count = rtp_packet_count * ts_packet_count_in_rtp;
+ int rtp_remain_size = rtp_size % (TS_PACKET_SIZE * ts_packet_count_in_rtp + RTP_HEADER_SIZE);
+ int ts_ramain_size = 0;
+
+ if (rtp_remain_size > 0) {
+ ts_ramain_size = rtp_remain_size - RTP_HEADER_SIZE;
+ ts_packet_count += ts_ramain_size / TS_PACKET_SIZE;
+ }
+ if (psi_enable)
+ ts_packet_count -= 3;
+
+ ts_continuity_counter += ts_packet_count;
+ ts_continuity_counter = ts_continuity_counter & 0xf;
+
+ return ts_continuity_counter;
+}
+
+static int increment_rtp_sequence_number(
+ int rtp_seq_num, int rtp_size,
+ int ts_packet_count_in_rtp)
+{
+ int rtp_packet_size = TS_PACKET_SIZE * ts_packet_count_in_rtp + RTP_HEADER_SIZE;
+ int rtp_packet_count = rtp_size / rtp_packet_size;
+
+ if (rtp_size % rtp_packet_size)
+ rtp_packet_count++;
+ rtp_packet_count += rtp_seq_num;
+ rtp_packet_count = rtp_packet_count & 0xFFFF;
+
+ return rtp_packet_count;
+}
+
+irqreturn_t tsmux_irq(int irq, void *priv)
+{
+ struct tsmux_device *tsmux_dev = priv;
+ struct tsmux_context *ctx;
+ int job_id;
+ int dst_len;
+ int i;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ tsmux_dev->irq = irq;
+ ctx = tsmux_dev->ctx[tsmux_dev->ctx_cur];
+
+ spin_lock(&tsmux_dev->device_spinlock);
+
+ if (tsmux_is_job_done_id_0(tsmux_dev)) {
+ job_id = 0;
+ print_tsmux(TSMUX_COMMON, "Job ID %d is done\n", job_id);
+ tsmux_clear_job_done(tsmux_dev, job_id);
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++)
+ if (ctx->otf_outbuf_info[i].buf_state == BUF_Q)
+ break;
+ dst_len = tsmux_get_dst_len(tsmux_dev, job_id);
+ print_tsmux(TSMUX_OTF, "otf outbuf num: %d, dst length: %d\n", i, dst_len);
+
+ if (i < TSMUX_OUT_BUF_CNT) {
+ ctx->otf_outbuf_info[i].buf_state = BUF_DONE;
+ ctx->otf_cmd_queue.out_buf[i].actual_size = dst_len;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+ ctx->tsmux_end_stamp = timestamp;
+ } else
+ print_tsmux(TSMUX_ERR, "wrong index: %d\n", i);
+
+ wake_up_interruptible(&ctx->otf_wait_queue);
+ }
+
+ if (tsmux_is_job_done_id_1(tsmux_dev)) {
+ job_id = 1;
+ print_tsmux(TSMUX_COMMON, "Job ID %d is done\n", job_id);
+ tsmux_clear_job_done(tsmux_dev, job_id);
+ ctx->m2m_job_done[get_m2m_buffer_idx(job_id)] = true;
+ }
+
+ if (tsmux_is_job_done_id_2(tsmux_dev)) {
+ job_id = 2;
+ print_tsmux(TSMUX_COMMON, "Job ID %d is done\n", job_id);
+ tsmux_clear_job_done(tsmux_dev, job_id);
+ ctx->m2m_job_done[get_m2m_buffer_idx(job_id)] = true;
+ }
+
+ if (tsmux_is_job_done_id_3(tsmux_dev)) {
+ job_id = 3;
+ print_tsmux(TSMUX_COMMON, "Job ID %d is done\n", job_id);
+ tsmux_clear_job_done(tsmux_dev, job_id);
+ ctx->m2m_job_done[get_m2m_buffer_idx(job_id)] = true;
+ }
+
+ spin_unlock(&tsmux_dev->device_spinlock);
+
+ if (is_m2m_job_done(ctx)) {
+ print_tsmux(TSMUX_COMMON, "wake_up_interruptible()\n");
+ wake_up_interruptible(&ctx->m2m_wait_queue);
+ }
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return IRQ_HANDLED;
+}
+
+static int tsmux_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev = container_of(filp->private_data,
+ struct tsmux_device, misc_dev);
+ struct tsmux_context *ctx;
+ unsigned long flags;
+ int i;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ if (tsmux_dev->ctx_cnt >= TSMUX_MAX_CONTEXTS_NUM) {
+ print_tsmux(TSMUX_ERR, "%s, too many context\n", __func__);
+ ret = -ENOMEM;
+ goto err_init;
+ }
+
+ ctx = kzalloc(sizeof(struct tsmux_context), GFP_KERNEL);
+ if (!ctx) {
+ ret = -ENOMEM;
+ goto err_init;
+ }
+
+ /* init ctx */
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ ctx->m2m_cmd_queue.m2m_job[i].in_buf.ion_buf_fd = -1;
+ ctx->m2m_cmd_queue.m2m_job[i].out_buf.ion_buf_fd = -1;
+ }
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++)
+ ctx->otf_cmd_queue.out_buf[i].ion_buf_fd = -1;
+
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ ctx->tsmux_dev = tsmux_dev;
+ ctx->ctx_num = tsmux_dev->ctx_cnt;
+ tsmux_dev->ctx[ctx->ctx_num] = ctx;
+ tsmux_dev->ctx_cnt++;
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ pm_runtime_get_sync(tsmux_dev->dev);
+ if (ret < 0) {
+ print_tsmux(TSMUX_ERR, "pm_runtime_get_sync err(%d)\n", ret);
+ return ret;
+ }
+#ifdef CLK_ENABLE
+ ret = clk_enable(tsmux_dev->tsmux_clock);
+ if (ret < 0) {
+ print_tsmux(TSMUX_ERR, "clk_enable err (%d)\n", ret);
+ return ret;
+ }
+#endif
+
+ ctx->audio_frame_count = 0;
+ ctx->video_frame_count = 0;
+ ctx->set_hex_info = true;
+
+ filp->private_data = ctx;
+ print_tsmux(TSMUX_COMMON, "filp->private_data 0x%p\n",
+ filp->private_data);
+
+ g_tsmux_dev = tsmux_dev;
+
+ init_waitqueue_head(&ctx->m2m_wait_queue);
+ init_waitqueue_head(&ctx->otf_wait_queue);
+
+ //print_tsmux_sfr(tsmux_dev);
+ //print_dbg_info_all(tsmux_dev);
+
+ tsmux_reset_pkt_ctrl(tsmux_dev);
+
+ //print_tsmux_sfr(tsmux_dev);
+ //print_dbg_info_all(tsmux_dev);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return ret;
+
+err_init:
+ print_tsmux(TSMUX_COMMON, "%s--, err_init\n", __func__);
+
+ return ret;
+}
+
+static int tsmux_release(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ struct tsmux_context *ctx = filp->private_data;
+ struct tsmux_device *tsmux_dev = ctx->tsmux_dev;
+ unsigned long flags;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ tsmux_clear_hex_ctrl();
+
+#ifdef CLK_ENABLE
+ clk_disable(tsmux_dev->tsmux_clock);
+#endif
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ ctx->tsmux_dev->ctx_cnt--;
+ kfree(ctx);
+ filp->private_data = NULL;
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ pm_runtime_put_sync(tsmux_dev->dev);
+ if (ret < 0) {
+ print_tsmux(TSMUX_ERR, "pm_runtime_put_sync err(%d)\n", ret);
+ return ret;
+ }
+
+ g_tsmux_dev = NULL;
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+ return ret;
+}
+
+int tsmux_set_info(struct tsmux_context *ctx,
+ struct tsmux_swp_ctrl *swp_ctrl,
+ struct tsmux_hex_ctrl *hex_ctrl)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ /* set swap_ctrl reg*/
+// tsmux_set_swp_ctrl(tsmux_dev, swp_ctrl);
+
+ /* secure OS will set hex regs */
+ tsmux_set_hex_ctrl(ctx, hex_ctrl);
+
+ /* enable interrupt */
+ tsmux_enable_int_job_done(tsmux_dev);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return ret;
+}
+
+int tsmux_job_queue(struct tsmux_context *ctx,
+ struct tsmux_pkt_ctrl *pkt_ctrl,
+ struct tsmux_pes_hdr *pes_hdr,
+ struct tsmux_ts_hdr *ts_hdr,
+ struct tsmux_rtp_hdr *rtp_hdr,
+ int32_t src_len,
+ struct tsmux_buffer_info *inbuf, struct tsmux_buffer_info *outbuf)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ /* set pck_ctrl */
+ tsmux_set_pkt_ctrl(tsmux_dev, pkt_ctrl);
+
+ /* set pes_hdr */
+ tsmux_set_pes_hdr(tsmux_dev, pes_hdr);
+
+ /* set ts_hdr */
+ tsmux_set_ts_hdr(tsmux_dev, ts_hdr);
+
+ /* set rtp_hdr */
+ tsmux_set_rtp_hdr(tsmux_dev, rtp_hdr);
+
+ /* set src_addr_reg */
+ tsmux_set_src_addr(tsmux_dev, inbuf);
+
+ /* set src_len_reg */
+ tsmux_set_src_len(tsmux_dev, src_len);
+
+ /* set dst_addr_reg */
+ tsmux_set_dst_addr(tsmux_dev, outbuf);
+
+ /* set pkt_ctrl_reg */
+ tsmux_job_queue_pkt_ctrl(tsmux_dev);
+
+ //print_tsmux_sfr(tsmux_dev);
+ //print_dbg_info_all(tsmux_dev);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return ret;
+}
+
+int tsmux_ioctl_m2m_map_buf(struct tsmux_context *ctx, int buf_fd, int buf_size,
+ struct tsmux_buffer_info *buf_info)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+
+ print_tsmux(TSMUX_M2M, "%s++\n", __func__);
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ print_tsmux(TSMUX_M2M, "map m2m in_buf\n");
+
+ buf_info->dmabuf = dma_buf_get(buf_fd);
+ print_tsmux(TSMUX_M2M, "dma_buf_get(%d) ret dmabuf %p\n",
+ buf_fd, buf_info->dmabuf);
+
+ buf_info->dmabuf_att = dma_buf_attach(buf_info->dmabuf, tsmux_dev->dev);
+ print_tsmux(TSMUX_M2M, "dma_buf_attach() ret dmabuf_att %p\n",
+ buf_info->dmabuf_att);
+
+ buf_info->dma_addr = ion_iovmm_map(buf_info->dmabuf_att, 0, buf_size,
+ DMA_TO_DEVICE, 0);
+ print_tsmux(TSMUX_M2M, "ion_iovmm_map() ret dma_addr_t 0x%llx\n",
+ buf_info->dma_addr);
+
+ print_tsmux(TSMUX_M2M, "%s--\n", __func__);
+
+ return ret;
+}
+
+int tsmux_ioctl_m2m_unmap_buf(struct tsmux_context *ctx,
+ struct tsmux_buffer_info *buf_info)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+ struct ion_client *client;
+
+ print_tsmux(TSMUX_M2M, "%s++\n", __func__);
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ tsmux_dev = ctx->tsmux_dev;
+ client = tsmux_dev->tsmux_ion_client;
+
+ print_tsmux(TSMUX_M2M, "unmap m2m in_buf\n");
+
+
+ if (buf_info->dma_addr) {
+ print_tsmux(TSMUX_M2M, "ion_iovmm_unmap(%p, 0x%llx)\n",
+ buf_info->dmabuf_att, buf_info->dma_addr);
+ ion_iovmm_unmap(buf_info->dmabuf_att, buf_info->dma_addr);
+ buf_info->dma_addr = 0;
+ }
+
+ if (buf_info->dmabuf_att) {
+ print_tsmux(TSMUX_M2M, "dma_buf_detach(%p, %p)\n",
+ buf_info->dmabuf, buf_info->dmabuf_att);
+ dma_buf_detach(buf_info->dmabuf, buf_info->dmabuf_att);
+ buf_info->dmabuf_att = 0;
+ }
+
+ if (buf_info->dmabuf) {
+ print_tsmux(TSMUX_M2M, "dma_buf_put(%p)\n", buf_info->dmabuf);
+ dma_buf_put(buf_info->dmabuf);
+ buf_info->dmabuf = 0;
+ }
+
+ print_tsmux(TSMUX_M2M, "%s--\n", __func__);
+
+ return ret;
+}
+
+int tsmux_ioctl_m2m_run(struct tsmux_context *ctx)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+ unsigned long flags;
+ struct tsmux_job *m2m_job;
+ int i = 0;
+ int dst_len;
+ int job_id;
+ uint8_t *psi_data = NULL;
+
+ print_tsmux(TSMUX_M2M, "%s++\n", __func__);
+
+ if (ctx == NULL)
+ return -EFAULT;
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ tsmux_dev->ctx_cur = ctx->ctx_num;
+
+ /* init job_done[] */
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ m2m_job = &ctx->m2m_cmd_queue.m2m_job[i];
+ if (m2m_job->pes_hdr.pts39_16 != -1)
+ ctx->m2m_job_done[i] = false;
+ else
+ ctx->m2m_job_done[i] = true;
+ print_tsmux(TSMUX_M2M, "ctx->m2m_job_done[%d] %d\n",
+ i, ctx->m2m_job_done[i]);
+ }
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ m2m_job = &ctx->m2m_cmd_queue.m2m_job[i];
+ if (m2m_job->pes_hdr.pts39_16 != -1) {
+ tsmux_set_info(ctx, &m2m_job->swp_ctrl, &m2m_job->hex_ctrl);
+
+ print_tsmux(TSMUX_COMMON, "m2m job_queue, seq 0x%x, over %d, a_cc %.2x, psi_en %d\n",
+ ctx->rtp_ts_info.rtp_seq_number,
+ ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_audio_cc,
+ m2m_job->pkt_ctrl.psi_en);
+
+ if (m2m_job->pkt_ctrl.psi_en) {
+ /* PAT CC should be set by tsmux device driver */
+ psi_data = (char *)ctx->psi_info.psi_data;
+ psi_data[3] |= ctx->rtp_ts_info.ts_pat_cc;
+ print_tsmux(TSMUX_M2M, "ts pat %.2x %.2x %.2x %.2x, ts_pat_cc %.2x, pat_len %d\n",
+ psi_data[0], psi_data[1], psi_data[2], psi_data[3],
+ ctx->rtp_ts_info.ts_pat_cc, ctx->psi_info.pat_len);
+ ctx->rtp_ts_info.ts_pat_cc++;
+ if (ctx->rtp_ts_info.ts_pat_cc == 16)
+ ctx->rtp_ts_info.ts_pat_cc = 0;
+ psi_data += ctx->psi_info.pat_len;
+
+ /* PMT CC should be set by tsmux device driver */
+ psi_data[3] |= ctx->rtp_ts_info.ts_pmt_cc;
+ print_tsmux(TSMUX_M2M, "ts pmt %.2x %.2x %.2x %.2x, ts_pmt_cc %.2x, pmt_len %d\n",
+ psi_data[0], psi_data[1], psi_data[2], psi_data[3],
+ ctx->rtp_ts_info.ts_pmt_cc, ctx->psi_info.pmt_len);
+ ctx->rtp_ts_info.ts_pmt_cc++;
+ if (ctx->rtp_ts_info.ts_pmt_cc == 16)
+ ctx->rtp_ts_info.ts_pmt_cc = 0;
+ psi_data += ctx->psi_info.pmt_len;
+
+ tsmux_set_psi_info(ctx->tsmux_dev, &ctx->psi_info);
+ }
+
+ if (ctx->rtp_ts_info.rtp_seq_override == 1) {
+ m2m_job->rtp_hdr.seq = ctx->rtp_ts_info.rtp_seq_number;
+ m2m_job->pkt_ctrl.rtp_seq_override = 1;
+ m2m_job->ts_hdr.continuity_counter = ctx->rtp_ts_info.ts_audio_cc;
+ ctx->rtp_ts_info.rtp_seq_override = 0;
+ } else {
+ m2m_job->pkt_ctrl.rtp_seq_override = 0;
+ }
+ m2m_job->ts_hdr.continuity_counter = ctx->rtp_ts_info.ts_audio_cc;
+
+ tsmux_job_queue(ctx,
+ &m2m_job->pkt_ctrl,
+ &m2m_job->pes_hdr,
+ &m2m_job->ts_hdr,
+ &m2m_job->rtp_hdr,
+ m2m_job->in_buf.actual_size,
+ &ctx->m2m_inbuf_info[i],
+ &ctx->m2m_outbuf_info[i]);
+ }
+ }
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ wait_event_interruptible_timeout(ctx->m2m_wait_queue,
+ is_m2m_job_done(ctx), usecs_to_jiffies(MAX_JOB_DONE_WAIT_TIME));
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ m2m_job = &ctx->m2m_cmd_queue.m2m_job[i];
+ if (m2m_job->pes_hdr.pts39_16 != -1) {
+ m2m_job->out_buf.offset = 0;
+ ctx->audio_frame_count++;
+ m2m_job->out_buf.time_stamp =
+ ctx->audio_frame_count * AUDIO_TIME_PERIOD_US;
+ job_id = get_m2m_job_id(i);
+ dst_len = tsmux_get_dst_len(tsmux_dev, job_id);
+ m2m_job->out_buf.actual_size = dst_len;
+ ctx->rtp_ts_info.ts_audio_cc = increment_ts_continuity_counter(
+ ctx->rtp_ts_info.ts_audio_cc, dst_len,
+ m2m_job->pkt_ctrl.rtp_size, m2m_job->pkt_ctrl.psi_en);
+ ctx->rtp_ts_info.rtp_seq_number = increment_rtp_sequence_number(
+ ctx->rtp_ts_info.rtp_seq_number, dst_len,
+ m2m_job->pkt_ctrl.rtp_size);
+ print_tsmux(TSMUX_COMMON, "m2m job_done, seq 0x%x, over %d, a_cc 0x%x\n",
+ ctx->rtp_ts_info.rtp_seq_number,
+ ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_audio_cc);
+
+ print_tsmux(TSMUX_M2M, "m2m %d, dst_len_reg %d",
+ i, dst_len);
+ }
+ }
+
+ print_tsmux(TSMUX_M2M, "%s--\n", __func__);
+
+ return ret;
+}
+
+int g2d_blending_start(int32_t index)
+{
+ int ret = 0;
+ struct tsmux_context *ctx = NULL;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+
+ if (g_tsmux_dev == NULL) {
+ print_tsmux(TSMUX_ERR, "tsmux was removed\n");
+ ret = -1;
+ return ret;
+ }
+
+ ctx = g_tsmux_dev->ctx[g_tsmux_dev->ctx_cur];
+
+ ctx->g2d_start_stamp[index] = timestamp;
+ print_tsmux(TSMUX_COMMON, "g2d_blending_start() index %d, start timestamp %lld\n",
+ index, timestamp);
+
+ return ret;
+}
+
+int g2d_blending_end(int32_t index)
+{
+ int ret = 0;
+ struct tsmux_context *ctx = NULL;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+
+ if (g_tsmux_dev == NULL) {
+ print_tsmux(TSMUX_ERR, "tsmux was removed\n");
+ ret = -1;
+ return ret;
+ }
+
+ ctx = g_tsmux_dev->ctx[g_tsmux_dev->ctx_cur];
+
+ ctx->g2d_end_stamp[index] = timestamp;
+ print_tsmux(TSMUX_COMMON, "g2d_blending_end() index %d, end timestamp %lld\n",
+ index, timestamp);
+
+ return ret;
+}
+
+int mfc_encoding_start(int32_t index)
+{
+ int ret = 0;
+ struct tsmux_context *ctx = NULL;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+
+ if (g_tsmux_dev == NULL) {
+ print_tsmux(TSMUX_ERR, "tsmux was removed\n");
+ ret = -1;
+ return ret;
+ }
+
+ ctx = g_tsmux_dev->ctx[g_tsmux_dev->ctx_cur];
+
+ ctx->mfc_start_stamp = timestamp;
+ ctx->mfc_encoding_index = index;
+
+ print_tsmux(TSMUX_COMMON, "mfc_encoding_start() index %d, start timestamp %lld\n",
+ ctx->mfc_encoding_index, timestamp);
+
+ return ret;
+}
+
+int mfc_encoding_end(void)
+{
+ int ret = 0;
+ struct tsmux_context *ctx = NULL;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+
+ if (g_tsmux_dev == NULL) {
+ print_tsmux(TSMUX_ERR, "tsmux was removed\n");
+ ret = -1;
+ return ret;
+ }
+
+ ctx = g_tsmux_dev->ctx[g_tsmux_dev->ctx_cur];
+
+ ctx->mfc_end_stamp = timestamp;
+ print_tsmux(TSMUX_COMMON, "mfc_encoding_end() end timestamp %lld\n",
+ timestamp);
+
+ return ret;
+}
+
+int packetize(struct packetizing_param *param)
+{
+ int ret = 0;
+ int index = -1;
+ int i = 0;
+ unsigned long flags;
+ struct tsmux_context *ctx = NULL;
+ struct tsmux_buffer_info *out_buf_info = NULL;
+ struct tsmux_otf_config *config = NULL;
+ uint8_t *psi_data = NULL;
+ uint64_t pcr;
+ uint64_t pcr_base;
+ uint32_t pcr_ext;
+ uint64_t pts = 0;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+
+ if (g_tsmux_dev == NULL) {
+ print_tsmux(TSMUX_ERR, "tsmux was removed\n");
+ ret = -1;
+ return ret;
+ }
+
+ ctx = g_tsmux_dev->ctx[g_tsmux_dev->ctx_cur];
+
+ spin_lock_irqsave(&g_tsmux_dev->device_spinlock, flags);
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ out_buf_info = &ctx->otf_outbuf_info[i];
+ if (out_buf_info->buf_state == BUF_Q) {
+ print_tsmux(TSMUX_ERR, "otf command queue is full\n");
+ ret = -1;
+ spin_unlock_irqrestore(&g_tsmux_dev->device_spinlock, flags);
+ return ret;
+ }
+ }
+
+ if (ctx->otf_outbuf_info[0].dma_addr == 0) {
+ print_tsmux(TSMUX_ERR, "otf_out_buf is NULL\n");
+ ret = -1;
+ spin_unlock_irqrestore(&g_tsmux_dev->device_spinlock, flags);
+ return ret;
+ }
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ out_buf_info = &ctx->otf_outbuf_info[i];
+ if (out_buf_info->buf_state == BUF_FREE) {
+ index = i;
+ print_tsmux(TSMUX_OTF, "otf buf index is %d\n", index);
+ break;
+ }
+ }
+
+ if (index == -1) {
+ print_tsmux(TSMUX_ERR, "otf buf full\n");
+ ret = -1;
+ spin_unlock_irqrestore(&g_tsmux_dev->device_spinlock, flags);
+ return ret;
+ }
+
+ ctx->tsmux_start_stamp = timestamp;
+
+ pts = (param->time_stamp * 9ll) / 100ll;
+ config = &ctx->otf_cmd_queue.config;
+
+ if (ctx->otf_cmd_queue.config.pkt_ctrl.psi_en == 1) {
+ /* PAT CC should be set by tsmux device driver */
+ psi_data = (char *)ctx->psi_info.psi_data;
+ psi_data[3] |= ctx->rtp_ts_info.ts_pat_cc;
+ print_tsmux(TSMUX_OTF, "ts pat %.2x %.2x %.2x %.2x, ts_pat_cc %.2x, pat_len %d\n",
+ psi_data[0], psi_data[1], psi_data[2], psi_data[3],
+ ctx->rtp_ts_info.ts_pat_cc, ctx->psi_info.pat_len);
+ ctx->rtp_ts_info.ts_pat_cc++;
+ if (ctx->rtp_ts_info.ts_pat_cc == 16)
+ ctx->rtp_ts_info.ts_pat_cc = 0;
+ psi_data += ctx->psi_info.pat_len;
+
+ /* PMT CC should be set by tsmux device driver */
+ psi_data[3] |= ctx->rtp_ts_info.ts_pmt_cc;
+ print_tsmux(TSMUX_OTF, "ts pmt %.2x %.2x %.2x %.2x, ts_pmt_cc %.2x, pmt_len %d\n",
+ psi_data[0], psi_data[1], psi_data[2], psi_data[3],
+ ctx->rtp_ts_info.ts_pmt_cc, ctx->psi_info.pmt_len);
+ ctx->rtp_ts_info.ts_pmt_cc++;
+ if (ctx->rtp_ts_info.ts_pmt_cc == 16)
+ ctx->rtp_ts_info.ts_pmt_cc = 0;
+ psi_data += ctx->psi_info.pmt_len;
+
+ /* PCR should be set by tsmux device driver */
+ pcr = param->time_stamp * 27; // PCR based on a 27MHz clock
+ pcr_base = pcr / 300;
+ pcr_ext = pcr % 300;
+
+ print_tsmux(TSMUX_OTF, "pcr header %.2x %.2x %.2x %.2x %.2x %.2x\n",
+ psi_data[0], psi_data[1], psi_data[2],
+ psi_data[3], psi_data[4], psi_data[5]);
+
+ psi_data += 6; // pcr ts packet header
+
+ *psi_data++ = (pcr_base >> 25) & 0xff;
+ *psi_data++ = (pcr_base >> 17) & 0xff;
+ *psi_data++ = (pcr_base >> 9) & 0xff;
+ *psi_data++ = ((pcr_base & 1) << 7) | 0x7e | ((pcr_ext >> 8) & 1);
+ *psi_data++ = (pcr_ext & 0xff);
+
+ tsmux_set_psi_info(ctx->tsmux_dev, &ctx->psi_info);
+ }
+
+ /* in case of otf, PTS should be set by tsmux device driver */
+ config->pes_hdr.pts39_16 = (0x20 | (((pts >> 30) & 7) << 1) | 1) << 16;
+ config->pes_hdr.pts39_16 |= ((pts >> 22) & 0xff) << 8;
+ config->pes_hdr.pts39_16 |= ((((pts >> 15) & 0x7f) << 1) | 1);
+ config->pes_hdr.pts15_0 = ((pts >> 7) & 0xff) << 8;
+ config->pes_hdr.pts15_0 |= (((pts & 0x7f) << 1) | 1);
+
+ tsmux_set_info(ctx, &config->swp_ctrl, &config->hex_ctrl);
+
+ print_tsmux(TSMUX_COMMON, "otf job_queue, seq 0x%x, over %d, v_cc 0x%x\n",
+ ctx->rtp_ts_info.rtp_seq_number, ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_video_cc);
+ if (ctx->rtp_ts_info.rtp_seq_override == 1) {
+ config->rtp_hdr.seq = ctx->rtp_ts_info.rtp_seq_number;
+ config->pkt_ctrl.rtp_seq_override = 1;
+ config->ts_hdr.continuity_counter = ctx->rtp_ts_info.ts_video_cc;
+ ctx->rtp_ts_info.rtp_seq_override = 0;
+ } else {
+ config->pkt_ctrl.rtp_seq_override = 0;
+ }
+ config->ts_hdr.continuity_counter = ctx->rtp_ts_info.ts_video_cc;
+
+ ret = tsmux_job_queue(ctx,
+ &config->pkt_ctrl,
+ &config->pes_hdr,
+ &config->ts_hdr,
+ &config->rtp_hdr,
+ 0, 0, &ctx->otf_outbuf_info[index]);
+ if (ret == 0) {
+ ctx->otf_cmd_queue.out_buf[index].time_stamp = param->time_stamp;
+ ctx->otf_outbuf_info[index].buf_state = BUF_Q;
+ print_tsmux(TSMUX_OTF, "otf buf status: BUF_FREE -> BUF_Q, index: %d\n", index);
+ }
+
+ spin_unlock_irqrestore(&g_tsmux_dev->device_spinlock, flags);
+
+ return ret;
+}
+
+void set_es_size(unsigned int size)
+{
+ print_tsmux(TSMUX_OTF, "es_size: %d\n", size);
+}
+
+static int get_job_done_buf(struct tsmux_context *ctx)
+{
+ struct tsmux_buffer_info *out_buf_info = NULL;
+ struct tsmux_buffer *user_info = NULL;
+ struct tsmux_device *tsmux_dev = ctx->tsmux_dev;
+ unsigned long flags;
+ int index = -1;
+ int i = 0;
+
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ out_buf_info = &ctx->otf_outbuf_info[i];
+ user_info = &ctx->otf_cmd_queue.out_buf[i];
+
+ if (out_buf_info->buf_state == BUF_DONE) {
+ if (index == -1)
+ index = i;
+ else {
+ if (ctx->otf_cmd_queue.out_buf[index].time_stamp
+ > user_info->time_stamp)
+ index = i;
+ }
+ }
+ }
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ return index;
+}
+
+static bool tsmux_ioctl_otf_dq_buf(struct tsmux_context *ctx)
+{
+ unsigned long wait_time = 0;
+ struct tsmux_device *tsmux_dev = ctx->tsmux_dev;
+ unsigned long flags;
+ int index = -1;
+ int out_size = 0;
+ int rtp_size = 0;
+ int psi_en = 0;
+ ktime_t ktime;
+ int64_t timestamp;
+
+ while ((index = get_job_done_buf(ctx)) == -1) {
+ wait_time = wait_event_interruptible_timeout(ctx->otf_wait_queue,
+ is_otf_job_done(ctx), HZ / 10);
+ print_tsmux(TSMUX_OTF, "dq buf wait_time: %lu\n", wait_time);
+ if (wait_time <= 0)
+ break;
+ }
+
+ if (wait_time > 0 || index != -1) {
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ out_size = ctx->otf_cmd_queue.out_buf[index].actual_size;
+ rtp_size = ctx->otf_cmd_queue.config.pkt_ctrl.rtp_size;
+ psi_en = ctx->otf_cmd_queue.config.pkt_ctrl.psi_en;
+
+ ctx->rtp_ts_info.ts_video_cc = increment_ts_continuity_counter(
+ ctx->rtp_ts_info.ts_video_cc, out_size, rtp_size, psi_en);
+#ifdef ADD_NULL_TS_PACKET
+ // TSMUX_HAL will add null ts packet after end of frame
+ ctx->rtp_ts_info.ts_video_cc++;
+ if (ctx->rtp_ts_info.ts_video_cc == 16)
+ ctx->rtp_ts_info.ts_video_cc = 0;
+#endif
+ ctx->rtp_ts_info.rtp_seq_number = increment_rtp_sequence_number(
+ ctx->rtp_ts_info.rtp_seq_number, out_size,
+ ctx->otf_cmd_queue.config.pkt_ctrl.rtp_size);
+
+ print_tsmux(TSMUX_COMMON, "otf job_done, seq 0x%x, over %d, v_cc 0x%x\n",
+ ctx->rtp_ts_info.rtp_seq_number, ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_video_cc);
+
+ ctx->otf_cmd_queue.cur_buf_num = index;
+ ctx->otf_outbuf_info[index].buf_state = BUF_DQ;
+ print_tsmux(TSMUX_OTF, "dq buf index: %d\n", index);
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+ } else {
+ print_tsmux(TSMUX_ERR, "time out: wait_time: %lu\n", wait_time);
+ return false;
+ }
+
+ ctx->otf_cmd_queue.out_buf[index].g2d_start_stamp = ctx->g2d_start_stamp[ctx->mfc_encoding_index];
+ ctx->otf_cmd_queue.out_buf[index].g2d_end_stamp = ctx->g2d_end_stamp[ctx->mfc_encoding_index];
+ ctx->otf_cmd_queue.out_buf[index].mfc_start_stamp = ctx->mfc_start_stamp;
+ ctx->otf_cmd_queue.out_buf[index].mfc_end_stamp = ctx->mfc_end_stamp;
+ ctx->otf_cmd_queue.out_buf[index].tsmux_start_stamp = ctx->tsmux_start_stamp;
+ ctx->otf_cmd_queue.out_buf[index].tsmux_end_stamp = ctx->tsmux_end_stamp;
+ ktime = ktime_get();
+ timestamp = ktime_to_us(ktime);
+ ctx->otf_cmd_queue.out_buf[index].kernel_end_stamp = timestamp;
+
+ print_tsmux(TSMUX_COMMON, "mfc_encoding_index %d, g2d %lld %lld\n",
+ ctx->mfc_encoding_index,
+ ctx->otf_cmd_queue.out_buf[index].g2d_start_stamp,
+ ctx->otf_cmd_queue.out_buf[index].g2d_end_stamp);
+
+ return true;
+}
+
+static bool tsmux_ioctl_otf_q_buf(struct tsmux_context *ctx)
+{
+ struct tsmux_device *tsmux_dev = ctx->tsmux_dev;
+ unsigned long flags;
+ int32_t index;
+
+ spin_lock_irqsave(&tsmux_dev->device_spinlock, flags);
+
+ index = ctx->otf_cmd_queue.cur_buf_num;
+ if (ctx->otf_outbuf_info[index].buf_state == BUF_DQ) {
+ ctx->otf_outbuf_info[index].buf_state = BUF_FREE;
+ print_tsmux(TSMUX_OTF, "otf buf status: BUF_DQ -> BUF_FREE, index: %d\n", index);
+ } else {
+ print_tsmux(TSMUX_ERR, "otf buf unexpected state: %d\n",
+ ctx->otf_outbuf_info[index].buf_state);
+ }
+
+ spin_unlock_irqrestore(&tsmux_dev->device_spinlock, flags);
+
+ return true;
+}
+
+static bool tsmux_ioctl_otf_map_buf(struct tsmux_context *ctx)
+{
+ int i = 0;
+ struct tsmux_buffer_info *out_buf_info = NULL;
+ struct tsmux_buffer *user_info = NULL;
+ struct tsmux_device *tsmux_dev = NULL;
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ print_tsmux(TSMUX_OTF, "map otf out_buf\n");
+
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ out_buf_info = &ctx->otf_outbuf_info[i];
+ user_info = &ctx->otf_cmd_queue.out_buf[i];
+
+ if (user_info->ion_buf_fd > 0) {
+ out_buf_info->dmabuf =
+ dma_buf_get(user_info->ion_buf_fd);
+ print_tsmux(TSMUX_OTF, "dma_buf_get(%d) ret dmabuf %p\n",
+ user_info->ion_buf_fd,
+ out_buf_info->dmabuf);
+
+ out_buf_info->dmabuf_att =
+ dma_buf_attach(out_buf_info->dmabuf,
+ tsmux_dev->dev);
+ print_tsmux(TSMUX_OTF, "dma_buf_attach() ret dmabuf_att %p\n",
+ out_buf_info->dmabuf_att);
+
+ out_buf_info->dma_addr =
+ ion_iovmm_map(out_buf_info->dmabuf_att,
+ 0, user_info->buffer_size,
+ DMA_TO_DEVICE, 0);
+ print_tsmux(TSMUX_OTF, "ion_iovmm_map() ret dma_addr_t 0x%llx\n",
+ out_buf_info->dma_addr);
+
+ out_buf_info->buf_state = BUF_FREE;
+ }
+ }
+
+ return true;
+}
+
+int tsmux_ioctl_otf_unmap_buf(struct tsmux_context *ctx)
+{
+ int i = 0;
+ struct tsmux_buffer_info *out_buf_info = NULL;
+ int ret = 0;
+
+ print_tsmux(TSMUX_OTF, "%s++\n", __func__);
+
+ if (ctx == NULL || ctx->tsmux_dev == NULL)
+ return -ENOMEM;
+
+ /* free otf buffer */
+ print_tsmux(TSMUX_OTF, "unmap otf out_buf\n");
+ for (i = 0; i < TSMUX_OUT_BUF_CNT; i++) {
+ out_buf_info = &ctx->otf_outbuf_info[i];
+
+ if (out_buf_info->dma_addr) {
+ print_tsmux(TSMUX_OTF, "ion_iovmm_unmmap(%p, 0x%llx)\n",
+ out_buf_info->dmabuf_att,
+ out_buf_info->dma_addr);
+ ion_iovmm_unmap(out_buf_info->dmabuf_att,
+ out_buf_info->dma_addr);
+ out_buf_info->dma_addr = 0;
+ }
+
+ print_tsmux(TSMUX_OTF, "ion_iovmm_unmap() ok\n");
+
+ if (out_buf_info->dmabuf_att) {
+ print_tsmux(TSMUX_OTF, "dma_buf_detach(%p, %p)\n",
+ out_buf_info->dmabuf,
+ out_buf_info->dmabuf_att);
+ dma_buf_detach(out_buf_info->dmabuf,
+ out_buf_info->dmabuf_att);
+ out_buf_info->dmabuf_att = 0;
+ }
+
+ print_tsmux(TSMUX_OTF, "dma_buf_detach() ok\n");
+
+ if (out_buf_info->dmabuf) {
+ print_tsmux(TSMUX_OTF, "dma_buf_put(%p)\n",
+ out_buf_info->dmabuf);
+ dma_buf_put(out_buf_info->dmabuf);
+ out_buf_info->dmabuf = 0;
+ }
+
+ print_tsmux(TSMUX_OTF, "dma_buf_put() ok\n");
+ }
+
+ print_tsmux(TSMUX_OTF, "%s--\n", __func__);
+
+ return ret;
+}
+
+static long tsmux_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ struct tsmux_context *ctx;
+ struct tsmux_device *tsmux_dev;
+ int i = 0;
+ int buf_fd = 0;
+ int buf_size = 0;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ ctx = filp->private_data;
+ if (!ctx) {
+ ret = -ENOTTY;
+ return ret;
+ }
+
+ tsmux_dev = ctx->tsmux_dev;
+
+ switch (cmd) {
+ case TSMUX_IOCTL_SET_INFO:
+ print_tsmux(TSMUX_COMMON, "TSMUX_IOCTL_SET_PSI\n");
+
+ if (copy_from_user(&(ctx->psi_info),
+ (struct tsmux_psi_info __user *)arg,
+ sizeof(struct tsmux_psi_info))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ tsmux_set_psi_info(ctx->tsmux_dev, &ctx->psi_info);
+ break;
+
+ case TSMUX_IOCTL_M2M_MAP_BUF:
+ print_tsmux(TSMUX_M2M, "TSMUX_IOCTL_M2M_MAP_BUF\n");
+
+ if (copy_from_user(&ctx->m2m_cmd_queue,
+ (struct tsmux_m2m_cmd_queue __user *)arg,
+ sizeof(struct tsmux_m2m_cmd_queue))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ buf_fd = ctx->m2m_cmd_queue.m2m_job[i].in_buf.ion_buf_fd;
+ buf_size = ctx->m2m_cmd_queue.m2m_job[i].in_buf.buffer_size;
+ if (buf_fd > 0 && buf_size > 0) {
+ tsmux_ioctl_m2m_map_buf(ctx, buf_fd, buf_size,
+ &ctx->m2m_inbuf_info[i]);
+ }
+ }
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ buf_fd = ctx->m2m_cmd_queue.m2m_job[i].out_buf.ion_buf_fd;
+ buf_size = ctx->m2m_cmd_queue.m2m_job[i].out_buf.buffer_size;
+ if (buf_fd > 0 && buf_size > 0) {
+ tsmux_ioctl_m2m_map_buf(ctx, buf_fd, buf_size,
+ &ctx->m2m_outbuf_info[i]);
+ }
+ }
+
+ if (copy_to_user((struct tsmux_m2m_cmd_queue __user *)arg,
+ &ctx->m2m_cmd_queue,
+ sizeof(struct tsmux_m2m_cmd_queue))) {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case TSMUX_IOCTL_M2M_UNMAP_BUF:
+ print_tsmux(TSMUX_M2M, "TSMUX_IOCTL_M2M_UNMAP_BUF\n");
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ buf_fd = ctx->m2m_cmd_queue.m2m_job[i].in_buf.ion_buf_fd;
+ buf_size = ctx->m2m_cmd_queue.m2m_job[i].in_buf.buffer_size;
+ if (buf_fd > 0 && buf_size > 0) {
+ tsmux_ioctl_m2m_unmap_buf(ctx,
+ &ctx->m2m_inbuf_info[i]);
+ }
+ }
+
+ for (i = 0; i < TSMUX_MAX_M2M_CMD_QUEUE_NUM; i++) {
+ buf_fd = ctx->m2m_cmd_queue.m2m_job[i].out_buf.ion_buf_fd;
+ buf_size = ctx->m2m_cmd_queue.m2m_job[i].out_buf.buffer_size;
+ if (buf_fd > 0 && buf_size > 0) {
+ tsmux_ioctl_m2m_unmap_buf(ctx,
+ &ctx->m2m_outbuf_info[i]);
+ }
+ }
+
+ break;
+
+ case TSMUX_IOCTL_M2M_RUN:
+ print_tsmux(TSMUX_M2M, "TSMUX_IOCTL_M2M_RUN\n");
+
+ if (copy_from_user(&ctx->m2m_cmd_queue,
+ (struct tsmux_m2m_cmd_queue __user *)arg,
+ sizeof(struct tsmux_m2m_cmd_queue))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ ret = tsmux_ioctl_m2m_run(ctx);
+
+ if (copy_to_user((struct tsmux_m2m_cmd_queue __user *)arg,
+ &ctx->m2m_cmd_queue,
+ sizeof(struct tsmux_m2m_cmd_queue))) {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case TSMUX_IOCTL_OTF_MAP_BUF:
+ print_tsmux(TSMUX_OTF, "TSMUX_IOCTL_OTF_MAP_BUF\n");
+ if (copy_from_user(&ctx->otf_cmd_queue,
+ (struct tsmux_otf_cmd_queue __user *)arg,
+ sizeof(struct tsmux_otf_cmd_queue))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (!tsmux_ioctl_otf_map_buf(ctx)) {
+ print_tsmux(TSMUX_ERR, "map fail for dst buf\n");
+ ret = -EFAULT;
+ break;
+ }
+
+ if (copy_to_user((struct tsmux_otf_cmd_queue __user *) arg,
+ &ctx->otf_cmd_queue, sizeof(struct tsmux_otf_cmd_queue))) {
+ print_tsmux(TSMUX_ERR, "TSMUX_IOCTL_OTF_OTF_BUF: fail to copy_to_user\n");
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case TSMUX_IOCTL_OTF_UNMAP_BUF:
+ print_tsmux(TSMUX_OTF, "TSMUX_IOCTL_OTF_REL_BUF\n");
+ tsmux_ioctl_otf_unmap_buf(ctx);
+ break;
+
+ case TSMUX_IOCTL_OTF_DQ_BUF:
+ print_tsmux(TSMUX_OTF, "TSMUX_IOCTL_OTF_DQ_BUF\n");
+ if (!tsmux_ioctl_otf_dq_buf(ctx)) {
+ print_tsmux(TSMUX_ERR, "dq buf fail\n");
+ ret = -EFAULT;
+ break;
+ }
+
+ if (copy_to_user((struct tsmux_otf_cmd_queue __user *) arg,
+ &ctx->otf_cmd_queue, sizeof(struct tsmux_otf_cmd_queue))) {
+ print_tsmux(TSMUX_ERR, "TSMUX_IOCTL_OTF_DQ_BUF: fail to copy_to_user\n");
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case TSMUX_IOCTL_OTF_Q_BUF:
+ print_tsmux(TSMUX_OTF, "TSMUX_IOCTL_OTF_Q_BUF\n");
+ if (copy_from_user(&ctx->otf_cmd_queue.cur_buf_num,
+ (int32_t *)arg,
+ sizeof(int32_t))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (!tsmux_ioctl_otf_q_buf(ctx))
+ ret = -EFAULT;
+ break;
+
+ case TSMUX_IOCTL_OTF_SET_CONFIG:
+ print_tsmux(TSMUX_OTF, "TSMUX_IOCTL_OTF_SET_CONFIG\n");
+ if (copy_from_user(&ctx->otf_cmd_queue.config,
+ (struct tsmux_otf_config __user *)arg,
+ sizeof(struct tsmux_otf_config))) {
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ case TSMUX_IOCTL_SET_RTP_TS_INFO:
+ if (copy_from_user(&ctx->rtp_ts_info,
+ (struct tsmux_rtp_ts_info __user *)arg,
+ sizeof(struct tsmux_rtp_ts_info))) {
+ ret = -EFAULT;
+ break;
+ }
+ print_tsmux(TSMUX_COMMON, "set, rtp 0x%x, overr %d, pat_cc 0x%x, pmt_cc 0x%x, v_cc 0x%x, a_cc 0x%x\n",
+ ctx->rtp_ts_info.rtp_seq_number, ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_pat_cc, ctx->rtp_ts_info.ts_pmt_cc,
+ ctx->rtp_ts_info.ts_video_cc, ctx->rtp_ts_info.ts_audio_cc);
+ break;
+
+ case TSMUX_IOCTL_GET_RTP_TS_INFO:
+ print_tsmux(TSMUX_COMMON, "TSMUX_IOCTL_GET_RTP_TS_INFO\n");
+ print_tsmux(TSMUX_COMMON, "get, rtp 0x%x, overr %d, pat_cc 0x%x, pmt_cc 0x%x, v_cc 0x%x, a_cc 0x%x\n",
+ ctx->rtp_ts_info.rtp_seq_number, ctx->rtp_ts_info.rtp_seq_override,
+ ctx->rtp_ts_info.ts_pat_cc, ctx->rtp_ts_info.ts_pmt_cc,
+ ctx->rtp_ts_info.ts_video_cc, ctx->rtp_ts_info.ts_audio_cc);
+ if (copy_to_user((struct tsmux_rtp_ts_info __user *) arg,
+ &ctx->rtp_ts_info, sizeof(struct tsmux_rtp_ts_info))) {
+ print_tsmux(TSMUX_ERR, "TSMUX_IOCTL_GET_RTP_TS_INFO: fail to copy_to_user\n");
+ ret = -EFAULT;
+ break;
+ }
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+ return ret;
+}
+
+static const struct file_operations tsmux_fops = {
+ .owner = THIS_MODULE,
+ .open = tsmux_open,
+ .release = tsmux_release,
+ .unlocked_ioctl = tsmux_ioctl,
+ .compat_ioctl = tsmux_ioctl,
+};
+
+static int tsmux_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct tsmux_device *tsmux_dev;
+ struct resource *res;
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ g_tsmux_debug_level = TSMUX_ERR;
+
+ tsmux_dev = devm_kzalloc(&pdev->dev, sizeof(struct tsmux_device),
+ GFP_KERNEL);
+ if (!tsmux_dev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ print_tsmux(TSMUX_ERR, "failed to get memory region resource\n");
+ ret = -ENOENT;
+ goto err_res_mem;
+ }
+
+ tsmux_dev->tsmux_mem = request_mem_region(res->start,
+ resource_size(res), pdev->name);
+ if (tsmux_dev->tsmux_mem == NULL) {
+ print_tsmux(TSMUX_ERR, "failed to get memory region\n");
+ ret = -ENOENT;
+ goto err_req_mem;
+ }
+
+ tsmux_dev->regs_base = ioremap(tsmux_dev->tsmux_mem->start,
+ resource_size(tsmux_dev->tsmux_mem));
+ if (tsmux_dev->regs_base == NULL) {
+ print_tsmux(TSMUX_ERR, "failed to ioremap address region\n");
+ ret = -ENOENT;
+ goto err_ioremap;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+ if (ret < 0) {
+ print_tsmux(TSMUX_ERR, "Failed to pm_runtime_enable (%d)\n", ret);
+ return ret;
+ }
+
+ iovmm_set_fault_handler(&pdev->dev, tsmux_iommu_fault_handler,
+ tsmux_dev);
+
+ ret = iovmm_activate(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to activate iommu\n");
+ goto err_iovmm_act;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ print_tsmux(TSMUX_ERR, "failed to get irq resource\n");
+ ret = -ENOENT;
+ goto err_res_irq;
+ }
+
+ tsmux_dev->irq = res->start;
+ ret = devm_request_irq(&pdev->dev, res->start, tsmux_irq,
+ 0, pdev->name, tsmux_dev);
+ if (ret != 0) {
+ print_tsmux(TSMUX_ERR, "failed to install irq (%d)\n", ret);
+ goto err_req_irq;
+ }
+#ifdef CLK_ENABLE
+ tsmux_dev->tsmux_clock = devm_clk_get(tsmux_dev->dev, "gate");
+ if (IS_ERR(tsmux_dev->tsmux_clock)) {
+ dev_err(tsmux_dev->dev, "Failed to get clock (%ld)\n",
+ PTR_ERR(tsmux_dev->tsmux_clock));
+ return PTR_ERR(tsmux_dev->tsmux_clock);
+ }
+#endif
+
+ spin_lock_init(&tsmux_dev->device_spinlock);
+
+ tsmux_dev->tsmux_ion_client = exynos_ion_client_create("tsmux");
+ if (tsmux_dev->tsmux_ion_client == NULL)
+ print_tsmux(TSMUX_ERR, "exynos_ion_client_create failed\n");
+
+ tsmux_dev->ctx_cnt = 0;
+
+ tsmux_dev->dev = &pdev->dev;
+ tsmux_dev->misc_dev.minor = MISC_DYNAMIC_MINOR;
+ tsmux_dev->misc_dev.fops = &tsmux_fops;
+ tsmux_dev->misc_dev.name = NODE_NAME;
+ ret = misc_register(&tsmux_dev->misc_dev);
+ if (ret)
+ goto err_misc_register;
+
+ platform_set_drvdata(pdev, tsmux_dev);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return ret;
+
+err_misc_register:
+ print_tsmux(TSMUX_ERR, "err_misc_dev\n");
+
+err_req_irq:
+err_res_irq:
+err_iovmm_act:
+err_ioremap:
+err_req_mem:
+err_res_mem:
+
+ return ret;
+}
+
+static int tsmux_remove(struct platform_device *pdev)
+{
+ struct tsmux_device *tsmux_dev = platform_get_drvdata(pdev);
+
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return -EFAULT;
+
+ iovmm_deactivate(tsmux_dev->dev);
+
+ if (tsmux_dev->tsmux_ion_client)
+ ion_client_destroy(tsmux_dev->tsmux_ion_client);
+
+ free_irq(tsmux_dev->irq, tsmux_dev);
+ iounmap(tsmux_dev->regs_base);
+
+ if (tsmux_dev) {
+ misc_deregister(&tsmux_dev->misc_dev);
+ kfree(tsmux_dev);
+ }
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+
+ return 0;
+}
+
+static void tsmux_shutdown(struct platform_device *pdev)
+{
+ print_tsmux(TSMUX_COMMON, "%s++\n", __func__);
+
+ print_tsmux(TSMUX_COMMON, "%s--\n", __func__);
+}
+
+static const struct of_device_id exynos_tsmux_match[] = {
+ {
+ .compatible = "samsung,exynos-tsmux",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, exynos_tsmux_match);
+
+static struct platform_driver tsmux_driver = {
+ .probe = tsmux_probe,
+ .remove = tsmux_remove,
+ .shutdown = tsmux_shutdown,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(exynos_tsmux_match),
+ }
+};
+
+module_platform_driver(tsmux_driver);
+
+MODULE_AUTHOR("Shinwon Lee <shinwon.lee@samsung.com>");
+MODULE_DESCRIPTION("EXYNOS tsmux driver");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Header file for Exynos TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef TSMUX_DEV_H
+#define TSMUX_DEV_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/types.h>
+#include <linux/dma-buf.h>
+#include <linux/ion.h>
+#include <linux/exynos_ion.h>
+#include <linux/wait.h>
+#include <media/exynos_tsmux.h>
+
+#include "tsmux.h"
+
+#define MAX_SHARED_BUFFER_NUM 3
+
+enum otf_buf_state {
+ BUF_FREE,
+ BUF_DONE,
+ BUF_DQ,
+ BUF_Q,
+};
+
+struct tsmux_buffer_info {
+ struct ion_handle *handle;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *dmabuf_att;
+ dma_addr_t dma_addr;
+ enum otf_buf_state buf_state;
+};
+
+struct tsmux_device {
+ struct miscdevice misc_dev;
+ struct device *dev;
+
+ void __iomem *regs_base;
+ struct resource *tsmux_mem;
+ struct clk *tsmux_clock;
+ int irq;
+
+ spinlock_t device_spinlock;
+
+ int ctx_cnt;
+ int ctx_cur;
+
+ struct tsmux_context *ctx[TSMUX_MAX_CONTEXTS_NUM];
+ struct ion_client *tsmux_ion_client;
+};
+
+struct tsmux_context {
+ struct tsmux_device *tsmux_dev;
+
+ struct tsmux_psi_info psi_info;
+ struct tsmux_m2m_cmd_queue m2m_cmd_queue;
+ struct tsmux_otf_cmd_queue otf_cmd_queue;
+
+ struct tsmux_buffer_info m2m_inbuf_info[TSMUX_MAX_M2M_CMD_QUEUE_NUM];
+ struct tsmux_buffer_info m2m_outbuf_info[TSMUX_MAX_M2M_CMD_QUEUE_NUM];
+ struct tsmux_buffer_info otf_outbuf_info[TSMUX_OUT_BUF_CNT];
+
+ struct tsmux_rtp_ts_info rtp_ts_info;
+
+ int es_size;
+ bool set_hex_info;
+
+ wait_queue_head_t m2m_wait_queue;
+ wait_queue_head_t otf_wait_queue;
+ bool m2m_job_done[TSMUX_MAX_M2M_CMD_QUEUE_NUM];
+
+ uint64_t audio_frame_count;
+ uint64_t video_frame_count;
+
+ int ctx_num;
+
+ uint64_t g2d_start_stamp[MAX_SHARED_BUFFER_NUM];
+ uint64_t g2d_end_stamp[MAX_SHARED_BUFFER_NUM];
+ uint32_t mfc_encoding_index;
+ uint64_t mfc_start_stamp;
+ uint64_t mfc_end_stamp;
+ uint64_t tsmux_start_stamp;
+ uint64_t tsmux_end_stamp;
+};
+
+#define NODE_NAME "tsmux"
+#define MODULE_NAME "exynos-tsmux"
+
+#define TSMUX_TIMEOUT 1000
+
+#endif /* TSMUX_DEV_H */
--- /dev/null
+/*
+ * copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <asm/uaccess.h>
+#include <linux/delay.h>
+
+#include "tsmux_dev.h"
+#include "tsmux_reg.h"
+#include "tsmux_dbg.h"
+
+#define TSMUX_READL(offset) \
+ (readl(tsmux_dev->regs_base + (offset)))
+#define TSMUX_WRITEL(data, offset) \
+ (writel((data), tsmux_dev->regs_base + (offset)))
+#define TSMUX_MASK(data, mask) (data & mask)
+
+#define TSMUX_PKT_CTRL_ADDR (0)
+#define TSMUX_PKT_CTRL_RESET_VALUE (0x3800)
+#define TSMUX_PKT_CTRL_SW_RESET_SHIFT (31)
+#define TSMUX_PKT_CTRL_SW_RESET_MASK (0x80000000)
+#define TSMUX_PKT_CTRL_PSI_EN_SHIFT (28)
+#define TSMUX_PKT_CTRL_PSI_EN_MASK (0x10000000)
+#define TSMUX_PKT_CTRL_RTP_SIZE_SHIFT (11)
+#define TSMUX_PKT_CTRL_RTP_SIZE_MASK (0x07FFF800)
+#define TSMUX_PKT_CTRL_RTP_SEQ_OVER_SHIFT (10)
+#define TSMUX_PKT_CTRL_RTP_SEQ_OVER_MASK (0x00000400)
+#define TSMUX_PKT_CTRL_PES_STUF_NUM_SHIFT (4)
+#define TSMUX_PKT_CTRL_PES_STUF_NUM_MASK (0x000003F0)
+#define TSMUX_PKT_CTRL_MODE_SHIFT (3)
+#define TSMUX_PKT_CTRL_MODE_MASK (0x00000008)
+#define TSMUX_PKT_CTRL_ID_SHIFT (1)
+#define TSMUX_PKT_CTRL_ID_MASK (0x00000006)
+#define TSMUX_PKT_CTRL_ENQUEUE_SHIFT (0)
+#define TSMUX_PKT_CTRL_ENQUEUE_MASK (0x00000001)
+
+#define TSMUX_SRC_BASE_ADDR (0x0004)
+#define TSMUX_SRC_BASE_RESET_VALUE (0x0)
+
+#define TSMUX_SRC_LEN_ADDR (0x0008)
+#define TSMUX_SRC_LEN_RESET_VALUE (0x0)
+
+#define TSMUX_DST_BASE_ADDR (0x000C)
+#define TSMUX_DST_BASE_RESET_VALUE (0x0)
+
+#define TSMUX_PES_HDR0_ADDR (0x0010)
+#define TSMUX_PES_HDR0_RESET_VALUE (0x0)
+#define TSMUX_PES_HDR0_CODE_VALUE (0x000001)
+#define TSMUX_PES_HDR0_CODE_SHIFT (8)
+#define TSMUX_PES_HDR0_CODE_MASK (0xFFFFFF00)
+#define TSMUX_PES_HDR0_STREAM_ID_SHIFT (0)
+#define TSMUX_PES_HDR0_STREAM_ID_MASK (0xFF)
+
+#define TSMUX_PES_HDR1_ADDR (0x0014)
+#define TSMUX_PES_HDR1_RESET_VALUE (0x0)
+#define TSMUX_PES_HDR1_PKT_LEN_SHIFT (16)
+#define TSMUX_PES_HDR1_PKT_LEN_MASK (0xFFFF0000)
+#define TSMUX_PES_HDR1_MARKER_VALUE (2)
+#define TSMUX_PES_HDR1_MARKER_SHIFT (14)
+#define TSMUX_PES_HDR1_MARKER_MASK (0x0000C000)
+#define TSMUX_PES_HDR1_SCRAMBLE_SHIFT (12)
+#define TSMUX_PES_HDR1_SCRAMBLE_MASK (0x00003000)
+#define TSMUX_PES_HDR1_PRIORITY_SHIFT (11)
+#define TSMUX_PES_HDR1_PRIORITY_MASK (0x00000800)
+#define TSMUX_PES_HDR1_ALIGNMENT_SHIFT (10)
+#define TSMUX_PES_HDR1_ALIGNMENT_MASK (0x00000400)
+#define TSMUX_PES_HDR1_COPYRIGHT_SHIFT (9)
+#define TSMUX_PES_HDR1_COPYRIGHT_MASK (0x00000200)
+#define TSMUX_PES_HDR1_ORIGINAL_SHIFT (8)
+#define TSMUX_PES_HDR1_ORIGINAL_MASK (0x00000100)
+#define TSMUX_PES_HDR1_FLAGS_PTS_VALUE (0x00000080)
+#define TSMUX_PES_HDR1_FLAGS_EXT_VALUE (0x00000001)
+#define TSMUX_PES_HDR1_FLAGS_MASK (0x000000FF)
+
+#define TSMUX_PES_HDR2_ADDR (0x0018)
+#define TSMUX_PES_HDR2_RESET_VALUE (0x0)
+#define TSMUX_PES_HDR2_HDR_LEN_SHIFT (24)
+#define TSMUX_PES_HDR2_HDR_LEN_MASK (0xFF000000)
+#define TSMUX_PES_HDR2_PTS39_16_SHIFT (0)
+#define TSMUX_PES_HDR2_PTS39_16_MASK (0x00FFFFFF)
+
+#define TSMUX_PES_HDR3_ADDR (0x001C)
+#define TSMUX_PES_HDR3_RESET_VALUE (0x0)
+#define TSMUX_PES_HDR3_PTS15_0_SHIFT (16)
+#define TSMUX_PES_HDR3_PTS15_0_MASK (0xFFFF0000)
+
+#define TSMUX_TSP_HDR_ADDR (0x0020)
+#define TSMUX_TSP_HDR_RESET_VALUE (0x0)
+#define TSMUX_TSP_HDR_SYNC_VALUE (0x47)
+#define TSMUX_TSP_HDR_SYNC_SHIFT (24)
+#define TSMUX_TSP_HDR_SYNC_MASK (0xFF000000)
+#define TSMUX_TSP_HDR_ERROR_SHIFT (23)
+#define TSMUX_TSP_HDR_ERROR_MASK (0x00800000)
+#define TSMUX_TSP_HDR_PRIORITY_SHIFT (21)
+#define TSMUX_TSP_HDR_PRIORITY_MASK (0x00200000)
+#define TSMUX_TSP_HDR_PID_SHIFT (8)
+#define TSMUX_TSP_HDR_PID_MASK (0x001FFF00)
+#define TSMUX_TSP_HDR_SCRAMBLE_SHIFT (0x6)
+#define TSMUX_TSP_HDR_SCRAMBLE_MASK (0x000000C0)
+#define TSMUX_TSP_HDR_ADAPT_CTRL_SHIFT (0x4)
+#define TSMUX_TSP_HDR_ADAPT_CTRL_MASK (0x00000030)
+#define TSMUX_TSP_HDR_CONT_CNT_SHIFT (0x0)
+#define TSMUX_TSP_HDR_CONT_CNT_MASK (0x0000000F)
+
+#define TSMUX_RTP_HDR0_ADDR (0x0024)
+#define TSMUX_RTP_HDR0_RESET_VALUE (0x0)
+#define TSMUX_RTP_HDR0_VER_VALUE (2)
+#define TSMUX_RTP_HDR0_VER_SHIFT (30)
+#define TSMUX_RTP_HDR0_VER_MASK (0xC0000000)
+#define TSMUX_RTP_HDR0_PAD_SHIFT (29)
+#define TSMUX_RTP_HDR0_PAD_MASK (0x20000000)
+#define TSMUX_RTP_HDR0_EXT_SHIFT (28)
+#define TSMUX_RTP_HDR0_EXT_MASK (0x10000000)
+#define TSMUX_RTP_HDR0_CSRC_CNT_SHIFT (24)
+#define TSMUX_RTP_HDR0_CSRC_CNT_MASK (0x0F000000)
+#define TSMUX_RTP_HDR0_MARKER_SHIFT (23)
+#define TSMUX_RTP_HDR0_MARKER_MASK (0x00800000)
+#define TSMUX_RTP_HDR0_PL_TYPE_SHIFT (16)
+#define TSMUX_RTP_HDR0_PL_TYPE_MASK (0x007F0000)
+#define TSMUX_RTP_HDR0_SEQ_SHIFT (0)
+#define TSMUX_RTP_HDR0_SEQ_MASK (0x0000FFFF)
+
+#define TSMUX_RTP_HDR2_ADDR (0x002C)
+#define TSMUX_RTP_HDR2_RESET_VALUE (0x0)
+#define TSMUX_RTP_HDR2_SSRC_SHIFT (0x0)
+#define TSMUX_RTP_HDR2_SSRC_MASK (0xFFFFFFFF)
+
+#define TSMUX_SWAP_CTRL_ADDR (0x0030)
+#define TSMUX_SWAP_CTRL_RESET_VALUE (0x0)
+#define TSMUX_SWAP_CTRL_INVERT_OUT4_SHIFT (3)
+#define TSMUX_SWAP_CTRL_INVERT_OUT4_MASK (0x00000008)
+#define TSMUX_SWAP_CTRL_INVERT_OUT1_SHIFT (2)
+#define TSMUX_SWAP_CTRL_INVERT_OUT1_MASK (0x00000004)
+#define TSMUX_SWAP_CTRL_INVERT_IN4_SHIFT (1)
+#define TSMUX_SWAP_CTRL_INVERT_IN4_MASK (0x00000002)
+#define TSMUX_SWAP_CTRL_INVERT_IN1_SHIFT (0)
+#define TSMUX_SWAP_CTRL_INVERT_IN1_MASK (0x00000001)
+
+#define TSMUX_PSI_LEN_ADDR (0x0034)
+#define TSMUX_PSI_LEN_RESET_VALUE (0x0)
+#define TSMUX_PSI_LEN_PCR_LEN_SHIFT (16)
+#define TSMUX_PSI_LEN_PCR_LEN_MASK (0x00FF0000)
+#define TSMUX_PSI_LEN_PMT_LEN_SHIFT (8)
+#define TSMUX_PSI_LEN_PMT_LEN_MASK (0x0000FF00)
+#define TSMUX_PSI_LEN_PAT_LEN_SHIFT (0)
+#define TSMUX_PSI_LEN_PAT_LEN_MASK (0x000000FF)
+
+#define TSMUX_PSI_DATA_NUM (64)
+#define TSMUX_PSI_DATA0_ADDR (0x0038)
+#define TSMUX_PSI_DATA0_RESET_VALUE (0x0)
+
+#define TSMUX_INT_EN_ADDR (0x0138)
+#define TSMUX_INT_EN_RESET_VALUE (0x0)
+#define TSMUX_INT_EN_PART_DONE (0x4)
+#define TSMUX_INT_EN_TIEM_OUT (0x2)
+#define TSMUX_INT_EN_JOB_DONE (0x1)
+
+#define TSMUX_INT_STAT_ADDR (0x013C)
+#define TSMUX_INT_STAT_RESET_VALUE (0x0)
+#define TSMUX_INT_STAT_PART_DONE_SHIFT (5)
+#define TSMUX_INT_STAT_PART_DONE_MASK (0x000001E0)
+#define TSMUX_INT_STAT_TIMEOUT_SHIFT (4)
+#define TSMUX_INT_STAT_TIMEOUT_MASK (0x00000010)
+#define TSMUX_INT_STAT_JOB_DONE_SHIFT (0)
+#define TSMUX_INT_STAT_JOB_DONE_MASK (0x0000000F)
+#define TSMUX_INT_STAT_JOB_ID_0_DONE (0x00000001)
+#define TSMUX_INT_STAT_JOB_ID_1_DONE (0x00000002)
+#define TSMUX_INT_STAT_JOB_ID_2_DONE (0x00000004)
+#define TSMUX_INT_STAT_JOB_ID_3_DONE (0x00000008)
+
+#define TSMUX_DBG_SEL_ADDR (0x0140)
+#define TSMUX_DBG_INFO_ADDR (0x0144)
+
+#define TSMUX_TIMEOUT_TH_ADDR (0x0148)
+
+#define TSMUX_CMD_CTRL_ADDR (0x014C)
+#define TSMUX_CMD_CTRL_RESET_VALUE (0x0)
+#define TSMUX_CMD_CTRL_MODE_SHIFT (1)
+#define TSMUX_CMD_CTRL_MODE_MASK (0x2)
+#define TSMUX_CMD_CTRL_MODE_CONSECUTIVE (0)
+#define TSMUX_CMD_CTRL_MODE_DEBUG (0)
+#define TSMUX_CMD_CTRL_CLEAR_SHIFT (0)
+#define TSMUX_CMD_CTRL_CLEAR_MASK (0x1)
+
+#define TSMUX_EXEC_CTRL_ADDR (0x0150)
+#define TSMUX_EXEC_CTRL_RESET_VALUE (0x0)
+#define TSMUX_EXEC_CTRL_NEXT_SHIFT (0)
+#define TSMUX_EXEC_CTRL_NEXT_MASK (0x1)
+
+#define TSMUX_PART_TH_ADDR (0x0154)
+#define TSMUX_DST_LEN0_ADDR (0x0158)
+#define TSMUX_DST_LEN1_ADDR (0x015C)
+#define TSMUX_DST_LEN2_ADDR (0x0160)
+#define TSMUX_DST_LEN3_ADDR (0x0164)
+
+#define TSMUX_LH_CTRL_ADDR (0x0168)
+#define TSMUX_LH_CTRL_RESET_VALUE (0x0)
+#define TSMUX_LH_CTRL_SYNCREQ_SHIFT (0)
+#define TSMUX_LH_CTRL_SYNCREQ_MASK (0x3)
+
+#define TSMUX_SHD_PKT_CTRL_ADDR (0x0800)
+#define TSMUX_SHD_SRC_BASE_ADDR (0x0804)
+#define TSMUX_SHD_SRC_LEN_ADDR (0x0808)
+#define TSMUX_SHD_DST_BASE_ADDR (0x080C)
+#define TSMUX_SHD_PES_HDR0_ADDR (0x0810)
+#define TSMUX_SHD_PES_HDR1_ADDR (0x0814)
+#define TSMUX_SHD_PES_HDR2_ADDR (0x0818)
+#define TSMUX_SHD_PES_HDR3_ADDR (0x081C)
+#define TSMUX_SHD_TS_HDR_ADDR (0x0820)
+#define TSMUX_SHD_RTP_HDR0_ADDR (0x0824)
+#define TSMUX_SHD_RTP_HDR2_ADDR (0x082C)
+
+#define TSMUX_HEX_BASE_ADDR (0x178F0000)
+
+#define TSMUX_HEX_M2M_CTRL (TSMUX_HEX_BASE_ADDR + 0x000)
+#define TSMUX_HEX_M2M_STAT (TSMUX_HEX_BASE_ADDR + 0x004)
+#define TSMUX_HEX_M2M_VER (TSMUX_HEX_BASE_ADDR + 0x00C)
+#define TSMUX_HEX_M2M_KEY3 (TSMUX_HEX_BASE_ADDR + 0x030)
+#define TSMUX_HEX_M2M_KEY2 (TSMUX_HEX_BASE_ADDR + 0x034)
+#define TSMUX_HEX_M2M_KEY1 (TSMUX_HEX_BASE_ADDR + 0x038)
+#define TSMUX_HEX_M2M_KEY0 (TSMUX_HEX_BASE_ADDR + 0x03C)
+#define TSMUX_HEX_M2M_CNT3 (TSMUX_HEX_BASE_ADDR + 0x040)
+#define TSMUX_HEX_M2M_CNT2 (TSMUX_HEX_BASE_ADDR + 0x044)
+#define TSMUX_HEX_M2M_CNT1 (TSMUX_HEX_BASE_ADDR + 0x048)
+#define TSMUX_HEX_M2M_CNT0 (TSMUX_HEX_BASE_ADDR + 0x04C)
+#define TSMUX_HEX_M2M_SCNT (TSMUX_HEX_BASE_ADDR + 0x050)
+
+#define TSMUX_HEX_OTF_CTRL (TSMUX_HEX_BASE_ADDR + 0x800)
+#define TSMUX_HEX_OTF_STAT (TSMUX_HEX_BASE_ADDR + 0x804)
+#define TSMUX_HEX_OTF_VER (TSMUX_HEX_BASE_ADDR + 0x80C)
+#define TSMUX_HEX_OTF_KEY3 (TSMUX_HEX_BASE_ADDR + 0x830)
+#define TSMUX_HEX_OTF_KEY2 (TSMUX_HEX_BASE_ADDR + 0x834)
+#define TSMUX_HEX_OTF_KEY1 (TSMUX_HEX_BASE_ADDR + 0x838)
+#define TSMUX_HEX_OTF_KEY0 (TSMUX_HEX_BASE_ADDR + 0x83C)
+#define TSMUX_HEX_OTF_CNT3 (TSMUX_HEX_BASE_ADDR + 0x840)
+#define TSMUX_HEX_OTF_CNT2 (TSMUX_HEX_BASE_ADDR + 0x844)
+#define TSMUX_HEX_OTF_CNT1 (TSMUX_HEX_BASE_ADDR + 0x848)
+#define TSMUX_HEX_OTF_CNT0 (TSMUX_HEX_BASE_ADDR + 0x84C)
+#define TSMUX_HEX_OTF_SCNT (TSMUX_HEX_BASE_ADDR + 0x850)
+
+#define TSMUX_HEX_DBG_CTRL (TSMUX_HEX_BASE_ADDR + 0xC00)
+
+void tsmux_print_dbg_info(struct tsmux_device *tsmux_dev,
+ u32 dbg_sel_reg)
+{
+ u32 dbg_info_reg;
+
+ if (tsmux_dev == NULL)
+ return;
+
+ TSMUX_WRITEL(dbg_sel_reg, TSMUX_DBG_SEL_ADDR);
+ udelay(10);
+ dbg_info_reg = TSMUX_READL(TSMUX_DBG_INFO_ADDR);
+ print_tsmux(TSMUX_DBG_SFR, "dbg_sel_reg 0x%.2x, dbg_info_reg 0x%.8x\n",
+ dbg_sel_reg, dbg_info_reg);
+}
+
+void tsmux_print_dbg_info_all(struct tsmux_device *tsmux_dev)
+{
+ if (tsmux_dev == NULL)
+ return;
+
+ tsmux_print_dbg_info(tsmux_dev, 0x00);
+ tsmux_print_dbg_info(tsmux_dev, 0x01);
+ tsmux_print_dbg_info(tsmux_dev, 0x02);
+ tsmux_print_dbg_info(tsmux_dev, 0x03);
+ tsmux_print_dbg_info(tsmux_dev, 0x04);
+ tsmux_print_dbg_info(tsmux_dev, 0x05);
+ tsmux_print_dbg_info(tsmux_dev, 0x10);
+ tsmux_print_dbg_info(tsmux_dev, 0x11);
+ tsmux_print_dbg_info(tsmux_dev, 0x20);
+ tsmux_print_dbg_info(tsmux_dev, 0x21);
+ tsmux_print_dbg_info(tsmux_dev, 0x22);
+ tsmux_print_dbg_info(tsmux_dev, 0x23);
+ tsmux_print_dbg_info(tsmux_dev, 0x30);
+ tsmux_print_dbg_info(tsmux_dev, 0x40);
+ tsmux_print_dbg_info(tsmux_dev, 0x50);
+ tsmux_print_dbg_info(tsmux_dev, 0x60);
+ tsmux_print_dbg_info(tsmux_dev, 0x70);
+ tsmux_print_dbg_info(tsmux_dev, 0x80);
+ tsmux_print_dbg_info(tsmux_dev, 0x90);
+ tsmux_print_dbg_info(tsmux_dev, 0xA0);
+ tsmux_print_dbg_info(tsmux_dev, 0xB0);
+ tsmux_print_dbg_info(tsmux_dev, 0xB1);
+ tsmux_print_dbg_info(tsmux_dev, 0xC0);
+ tsmux_print_dbg_info(tsmux_dev, 0xD0);
+ tsmux_print_dbg_info(tsmux_dev, 0xD1);
+ tsmux_print_dbg_info(tsmux_dev, 0xD2);
+ tsmux_print_dbg_info(tsmux_dev, 0xD3);
+ tsmux_print_dbg_info(tsmux_dev, 0xE0);
+ tsmux_print_dbg_info(tsmux_dev, 0xE1);
+ tsmux_print_dbg_info(tsmux_dev, 0xE2);
+ tsmux_print_dbg_info(tsmux_dev, 0xE3);
+ tsmux_print_dbg_info(tsmux_dev, 0xE4);
+ tsmux_print_dbg_info(tsmux_dev, 0xE5);
+ tsmux_print_dbg_info(tsmux_dev, 0xF0);
+}
+
+void tsmux_print_tsmux_sfr(struct tsmux_device *tsmux_dev)
+{
+ u32 i;
+ u32 sfr1, sfr2, sfr3, sfr4;
+
+ if (tsmux_dev == NULL)
+ return;
+
+ for (i = TSMUX_PKT_CTRL_ADDR; i <= TSMUX_LH_CTRL_ADDR; i += 16) {
+ sfr1 = TSMUX_READL(i);
+ sfr2 = TSMUX_READL(i + 4);
+ sfr3 = TSMUX_READL(i + 8);
+ sfr4 = TSMUX_READL(i + 12);
+ print_tsmux(TSMUX_SFR, "%.8x: %.8x %.8x %.8x %.8x\n",
+ i, sfr1, sfr2, sfr3, sfr4);
+ }
+
+ for (i = TSMUX_SHD_PKT_CTRL_ADDR; i <= TSMUX_SHD_RTP_HDR2_ADDR;
+ i += 16) {
+ sfr1 = TSMUX_READL(i);
+ sfr2 = TSMUX_READL(i + 4);
+ sfr3 = TSMUX_READL(i + 8);
+ sfr4 = TSMUX_READL(i + 12);
+ print_tsmux(TSMUX_SFR, "%.8x: %.8x %.8x %.8x %.8x\n",
+ i, sfr1, sfr2, sfr3, sfr4);
+ }
+}
+
+void tsmux_set_psi_info(struct tsmux_device *tsmux_dev,
+ struct tsmux_psi_info *psi_info)
+{
+ u32 psi_len_reg;
+ int i;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || psi_info == NULL)
+ return;
+
+ print_tsmux(TSMUX_SFR, "pcr_len %d, pmt_len %d, pat_len %d\n",
+ psi_info->pcr_len, psi_info->pmt_len, psi_info->pat_len);
+
+ /* set psi_leng */
+ psi_len_reg = TSMUX_PSI_LEN_PCR_LEN_MASK &
+ (psi_info->pcr_len << TSMUX_PSI_LEN_PCR_LEN_SHIFT);
+
+ psi_len_reg |= TSMUX_PSI_LEN_PMT_LEN_MASK &
+ (psi_info->pmt_len << TSMUX_PSI_LEN_PMT_LEN_SHIFT);
+
+ psi_len_reg |= TSMUX_PSI_LEN_PAT_LEN_MASK &
+ (psi_info->pat_len << TSMUX_PSI_LEN_PAT_LEN_SHIFT);
+
+ print_tsmux(TSMUX_SFR, "psi_len_reg 0x%x\n", psi_len_reg);
+
+ TSMUX_WRITEL(psi_len_reg, TSMUX_PSI_LEN_ADDR);
+
+ print_tsmux(TSMUX_SFR, "psi_len_reg 0x%x\n", psi_len_reg);
+
+ /* set psi_data */
+ for (i = 0; i < TSMUX_PSI_SIZE; i++) {
+ print_tsmux(TSMUX_SFR, "psi_data[%d] %u\n", i,
+ psi_info->psi_data[i]);
+ TSMUX_WRITEL(psi_info->psi_data[i],
+ TSMUX_PSI_DATA0_ADDR + i * 4);
+ }
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_pkt_ctrl(struct tsmux_device *tsmux_dev,
+ struct tsmux_pkt_ctrl *pkt_ctrl)
+{
+ u32 pkt_ctrl_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || pkt_ctrl == NULL)
+ return;
+
+ /* set pck_ctrl */
+ pkt_ctrl_reg = TSMUX_READL(TSMUX_PKT_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_PSI_EN_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_PSI_EN_MASK &
+ (pkt_ctrl->psi_en << TSMUX_PKT_CTRL_PSI_EN_SHIFT);
+ print_tsmux(TSMUX_SFR, "PKT_CTRL_PSI_EN %d\n", pkt_ctrl->psi_en);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_RTP_SIZE_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_RTP_SIZE_MASK &
+ (pkt_ctrl->rtp_size << TSMUX_PKT_CTRL_RTP_SIZE_SHIFT);
+ print_tsmux(TSMUX_SFR, "PKT_CTRL_RTP_SIZE %d\n",
+ pkt_ctrl->rtp_size);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_RTP_SEQ_OVER_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_RTP_SEQ_OVER_MASK &
+ (pkt_ctrl->rtp_seq_override <<
+ TSMUX_PKT_CTRL_RTP_SEQ_OVER_SHIFT);
+ print_tsmux(TSMUX_SFR, "PKT_CTRL_RTP_SEQ_OVER %d\n",
+ pkt_ctrl->rtp_seq_override);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_PES_STUF_NUM_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_PES_STUF_NUM_MASK &
+ (pkt_ctrl->pes_stuffing_num <<
+ TSMUX_PKT_CTRL_PES_STUF_NUM_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSMUX_PKT_CTRL_PES_STUF %d\n",
+ pkt_ctrl->pes_stuffing_num);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_MODE_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_MODE_MASK &
+ (pkt_ctrl->mode << TSMUX_PKT_CTRL_MODE_SHIFT);
+ print_tsmux(TSMUX_SFR, "PKT_CTRL_MODE %d\n", pkt_ctrl->mode);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_ID_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_ID_MASK &
+ (pkt_ctrl->id << TSMUX_PKT_CTRL_ID_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSMUX_PKT_CTRL_ID %d\n", pkt_ctrl->id);
+ print_tsmux(TSMUX_SFR, "pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ TSMUX_WRITEL(pkt_ctrl_reg, TSMUX_PKT_CTRL_ADDR);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_pes_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_pes_hdr *pes_hdr)
+{
+ u32 pes_hdr0_reg, pes_hdr1_reg, pes_hdr2_reg, pes_hdr3_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || pes_hdr == NULL)
+ return;
+
+ /* set pes_hdr0 */
+ pes_hdr0_reg = TSMUX_PES_HDR0_CODE_MASK &
+ (pes_hdr->code << TSMUX_PES_HDR0_CODE_SHIFT);
+
+ pes_hdr0_reg &= ~(TSMUX_PES_HDR0_STREAM_ID_MASK);
+ pes_hdr0_reg |= TSMUX_PES_HDR0_STREAM_ID_MASK &
+ (pes_hdr->stream_id << TSMUX_PES_HDR0_STREAM_ID_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR0_STREAM_ID %d\n", pes_hdr->stream_id);
+
+ TSMUX_WRITEL(pes_hdr0_reg, TSMUX_PES_HDR0_ADDR);
+ print_tsmux(TSMUX_SFR, "pes_hdr0_reg 0x%x\n", pes_hdr0_reg);
+
+ /* set pes_hdr1 */
+ pes_hdr1_reg = TSMUX_PES_HDR1_PKT_LEN_MASK &
+ (pes_hdr->pkt_len << TSMUX_PES_HDR1_PKT_LEN_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_PKT_LEN %d\n", pes_hdr->pkt_len);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_MARKER_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_MARKER_MASK &
+ (pes_hdr->marker << TSMUX_PES_HDR1_MARKER_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_MARKER %d\n", pes_hdr->marker);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_SCRAMBLE_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_SCRAMBLE_MASK &
+ (pes_hdr->scramble << TSMUX_PES_HDR1_SCRAMBLE_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_SCRAMBLE %d\n", pes_hdr->scramble);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_PRIORITY_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_PRIORITY_MASK &
+ (pes_hdr->priority << TSMUX_PES_HDR1_PRIORITY_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_PRIORITY %d\n", pes_hdr->priority);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_ALIGNMENT_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_ALIGNMENT_MASK &
+ (pes_hdr->alignment << TSMUX_PES_HDR1_ALIGNMENT_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_ALIGNMENT %d\n", pes_hdr->alignment);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_COPYRIGHT_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_COPYRIGHT_MASK &
+ (pes_hdr->copyright << TSMUX_PES_HDR1_COPYRIGHT_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_COPYRIGHT %d\n", pes_hdr->copyright);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_ORIGINAL_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_ORIGINAL_MASK &
+ (pes_hdr->original << TSMUX_PES_HDR1_ORIGINAL_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_ORIGINAL %d\n", pes_hdr->original);
+
+ pes_hdr1_reg &= ~(TSMUX_PES_HDR1_FLAGS_MASK);
+ pes_hdr1_reg |= TSMUX_PES_HDR1_FLAGS_MASK & (pes_hdr->flags);
+ print_tsmux(TSMUX_SFR, "PES_HDR1_FLAGS_PTS %d\n", pes_hdr->flags);
+
+ TSMUX_WRITEL(pes_hdr1_reg, TSMUX_PES_HDR1_ADDR);
+ print_tsmux(TSMUX_SFR, "pes_hdr1_reg 0x%x\n", pes_hdr1_reg);
+
+ /* set pes_hdr2 */
+ pes_hdr2_reg = TSMUX_PES_HDR2_HDR_LEN_MASK &
+ (pes_hdr->hdr_len << TSMUX_PES_HDR2_HDR_LEN_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR2_HDR_LEN %d\n", pes_hdr->hdr_len);
+
+ pes_hdr2_reg &= ~(TSMUX_PES_HDR2_PTS39_16_MASK);
+ pes_hdr2_reg |= TSMUX_PES_HDR2_PTS39_16_MASK &
+ (pes_hdr->pts39_16 << TSMUX_PES_HDR2_PTS39_16_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR2_PTS39_16 %u\n", pes_hdr->pts39_16);
+
+ TSMUX_WRITEL(pes_hdr2_reg, TSMUX_PES_HDR2_ADDR);
+ print_tsmux(TSMUX_SFR, "pes_hdr2_reg 0x%x\n", pes_hdr2_reg);
+
+ /* set pes_hdr3 */
+ pes_hdr3_reg = TSMUX_PES_HDR3_PTS15_0_MASK &
+ (pes_hdr->pts15_0 << TSMUX_PES_HDR3_PTS15_0_SHIFT);
+ print_tsmux(TSMUX_SFR, "PES_HDR2_PTS15_0 %u\n", pes_hdr->pts15_0);
+
+ TSMUX_WRITEL(pes_hdr3_reg, TSMUX_PES_HDR3_ADDR);
+ print_tsmux(TSMUX_SFR, "pes_hdr3_reg 0x%x\n", pes_hdr3_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_ts_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_ts_hdr *ts_hdr)
+{
+ u32 ts_hdr_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || ts_hdr == NULL)
+ return;
+
+ ts_hdr_reg = TSMUX_TSP_HDR_SYNC_MASK &
+ (ts_hdr->sync << TSMUX_TSP_HDR_SYNC_SHIFT);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_ERROR_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_ERROR_MASK &
+ (ts_hdr->error << TSMUX_TSP_HDR_ERROR_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_ERROR %d\n", ts_hdr->error);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_PRIORITY_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_PRIORITY_MASK &
+ (ts_hdr->priority << TSMUX_TSP_HDR_PRIORITY_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_PRIORITY %d\n", ts_hdr->priority);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_PID_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_PID_MASK &
+ (ts_hdr->pid << TSMUX_TSP_HDR_PID_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_PID %d\n", ts_hdr->pid);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_SCRAMBLE_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_SCRAMBLE_MASK &
+ (ts_hdr->scramble << TSMUX_TSP_HDR_SCRAMBLE_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_SCRAMBLE %d\n", ts_hdr->scramble);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_ADAPT_CTRL_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_ADAPT_CTRL_MASK &
+ (ts_hdr->adapt_ctrl << TSMUX_TSP_HDR_ADAPT_CTRL_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_ADAPT_CTRL %d\n", ts_hdr->adapt_ctrl);
+
+ ts_hdr_reg &= ~(TSMUX_TSP_HDR_CONT_CNT_MASK);
+ ts_hdr_reg |= TSMUX_TSP_HDR_CONT_CNT_MASK &
+ (ts_hdr->continuity_counter << TSMUX_TSP_HDR_CONT_CNT_SHIFT);
+ print_tsmux(TSMUX_SFR, "TSP_HDR_CONTINUITY_COUNTER %d\n",
+ ts_hdr->continuity_counter);
+
+ TSMUX_WRITEL(ts_hdr_reg, TSMUX_TSP_HDR_ADDR);
+ print_tsmux(TSMUX_SFR, "ts_hdr_reg 0x%x\n", ts_hdr_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_rtp_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_rtp_hdr *rtp_hdr)
+{
+ u32 rtp_hdr0_reg, rtp_hdr2_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || rtp_hdr == NULL)
+ return;
+
+ /* set rtp_hdr0 */
+ rtp_hdr0_reg = TSMUX_RTP_HDR0_VER_MASK &
+ (rtp_hdr->ver << TSMUX_RTP_HDR0_VER_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR0_VER %d\n", rtp_hdr->ver);
+
+ rtp_hdr0_reg &= ~(TSMUX_RTP_HDR0_PAD_MASK);
+ rtp_hdr0_reg |= TSMUX_RTP_HDR0_PAD_MASK &
+ (rtp_hdr->pad << TSMUX_RTP_HDR0_PAD_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR0_PAD %d\n", rtp_hdr->pad);
+
+ rtp_hdr0_reg &= ~(TSMUX_RTP_HDR0_MARKER_MASK);
+ rtp_hdr0_reg |= TSMUX_RTP_HDR0_MARKER_MASK &
+ (rtp_hdr->marker << TSMUX_RTP_HDR0_MARKER_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR0_MARKER %d\n", rtp_hdr->marker);
+
+ rtp_hdr0_reg &= ~(TSMUX_RTP_HDR0_PL_TYPE_MASK);
+ rtp_hdr0_reg |= TSMUX_RTP_HDR0_PL_TYPE_MASK &
+ (rtp_hdr->pl_type <<
+ TSMUX_RTP_HDR0_PL_TYPE_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR0_PL_TYPE %d\n", rtp_hdr->pl_type);
+
+ rtp_hdr0_reg &= ~(TSMUX_RTP_HDR0_SEQ_MASK);
+ rtp_hdr0_reg |= TSMUX_RTP_HDR0_SEQ_MASK &
+ (rtp_hdr->seq << TSMUX_RTP_HDR0_SEQ_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR0_SEQ %d\n", rtp_hdr->seq);
+
+ TSMUX_WRITEL(rtp_hdr0_reg, TSMUX_RTP_HDR0_ADDR);
+ print_tsmux(TSMUX_SFR, "rtp_hdr0_reg 0x%x\n", rtp_hdr0_reg);
+
+ /* set rtp_hdr2 */
+ rtp_hdr2_reg = TSMUX_RTP_HDR2_SSRC_MASK &
+ (rtp_hdr->ssrc << TSMUX_RTP_HDR2_SSRC_SHIFT);
+ print_tsmux(TSMUX_SFR, "RTP_HDR2_SSRC %u\n", rtp_hdr->ssrc);
+
+ TSMUX_WRITEL(rtp_hdr2_reg, TSMUX_RTP_HDR2_ADDR);
+ print_tsmux(TSMUX_SFR, "rtp_hdr2_reg 0x%x\n", rtp_hdr2_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_swp_ctrl(struct tsmux_device *tsmux_dev,
+ struct tsmux_swp_ctrl *swp_ctrl)
+{
+ u32 swap_ctrl_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || swp_ctrl == NULL)
+ return;
+
+ /* set swap_ctrl reg*/
+ swap_ctrl_reg = TSMUX_SWAP_CTRL_INVERT_OUT4_MASK &
+ (swp_ctrl->swap_ctrl_out4 << TSMUX_SWAP_CTRL_INVERT_OUT4_SHIFT);
+ swap_ctrl_reg |= TSMUX_SWAP_CTRL_INVERT_OUT1_MASK &
+ (swp_ctrl->swap_ctrl_out1 << TSMUX_SWAP_CTRL_INVERT_OUT1_SHIFT);
+ swap_ctrl_reg |= TSMUX_SWAP_CTRL_INVERT_IN4_MASK &
+ (swp_ctrl->swap_ctrl_in4 << TSMUX_SWAP_CTRL_INVERT_IN4_SHIFT);
+ swap_ctrl_reg |= TSMUX_SWAP_CTRL_INVERT_IN1_MASK &
+ (swp_ctrl->swap_ctrl_in1 << TSMUX_SWAP_CTRL_INVERT_IN1_SHIFT);
+
+ TSMUX_WRITEL(swap_ctrl_reg, TSMUX_SWAP_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "swap_ctrl_reg 0x%x\n", swap_ctrl_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+#include <linux/smc.h>
+void tsmux_clear_hex_ctrl(void)
+{
+ int ret;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+#ifndef ASB_WORK
+ ret = exynos_smc(0x82004014, 1, 0, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "hex sfr clear is failed\n");
+#else
+ ret = exynos_smc(0x82004007, TSMUX_HEX_M2M_CTRL, 0, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "smc failed\n");
+
+ ret = exynos_smc(0x82004007, TSMUX_HEX_OTF_CTRL, 0, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "smc failed\n");
+#endif
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_hex_ctrl(struct tsmux_context *ctx,
+ struct tsmux_hex_ctrl *hex_ctrl)
+{
+ int ret;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (hex_ctrl->m2m_enable == 0 && hex_ctrl->otf_enable == 0) {
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+ return;
+ }
+
+#ifndef ASB_WORK
+ if (ctx->set_hex_info) {
+ /* exynos_smc(0x82004014, m2m/otf mode, 0, enabled) */
+ ret = exynos_smc(0x82004014, 1, 0, 1);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "hex sfr setting is failed\n");
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CTRL %u\n", hex_ctrl->otf_enable);
+ ctx->set_hex_info = false;
+ }
+#else
+ ret = exynos_smc(0x82004007, TSMUX_HEX_M2M_CTRL, 0, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "smc failed\n");
+
+ ret = exynos_smc(0x82004007, TSMUX_HEX_OTF_CTRL, 0, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "smc failed\n");
+
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_KEY3, hex_ctrl->m2m_key[3], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_KEY2, hex_ctrl->m2m_key[2], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_KEY1, hex_ctrl->m2m_key[1], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_KEY0, hex_ctrl->m2m_key[0], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_CNT3, hex_ctrl->m2m_cnt[3], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_CNT2, hex_ctrl->m2m_cnt[2], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_CNT1, hex_ctrl->m2m_cnt[1], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_CNT0, hex_ctrl->m2m_cnt[0], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_M2M_SCNT, hex_ctrl->m2m_stream_cnt, 0);
+
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_KEY3, hex_ctrl->otf_key[3], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_KEY2, hex_ctrl->otf_key[2], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_KEY1, hex_ctrl->otf_key[1], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_KEY0, hex_ctrl->otf_key[0], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_CNT3, hex_ctrl->otf_cnt[3], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_CNT2, hex_ctrl->otf_cnt[2], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_CNT1, hex_ctrl->otf_cnt[1], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_CNT0, hex_ctrl->otf_cnt[0], 0);
+ exynos_smc(0x82004007, TSMUX_HEX_OTF_SCNT, hex_ctrl->otf_stream_cnt, 0);
+
+ ret = exynos_smc(0x82004007, TSMUX_HEX_M2M_CTRL, hex_ctrl->m2m_enable, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "exynos_smc(m2m_enable) failed\n");
+
+ ret = exynos_smc(0x82004007, TSMUX_HEX_OTF_CTRL, hex_ctrl->otf_enable, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "exynos_smc(otf_enable) failedsmc failed\n");
+
+ ret = exynos_smc(0x82004007, TSMUX_HEX_DBG_CTRL, hex_ctrl->dbg_ctrl_bypass, 0);
+ if (ret)
+ print_tsmux(TSMUX_ERR, "exynos_smc(dbg_ctrl_bypass) failed\n");
+
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_CTRL %u\n", hex_ctrl->m2m_enable);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_KEY3 %u\n", hex_ctrl->m2m_key[3]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_KEY2 %u\n", hex_ctrl->m2m_key[2]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_KEY1 %u\n", hex_ctrl->m2m_key[1]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_KEY0 %u\n", hex_ctrl->m2m_key[0]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_CNT3 %u\n", hex_ctrl->m2m_cnt[3]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_CNT2 %u\n", hex_ctrl->m2m_cnt[2]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_CNT1 %u\n", hex_ctrl->m2m_cnt[1]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_CNT0 %u\n", hex_ctrl->m2m_cnt[0]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_M2M_STREAM_CNT %u\n",
+ hex_ctrl->m2m_stream_cnt);
+
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CTRL %u\n", hex_ctrl->otf_enable);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_KEY3 %u\n", hex_ctrl->otf_key[3]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_KEY2 %u\n", hex_ctrl->otf_key[2]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_KEY1 %u\n", hex_ctrl->otf_key[1]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_KEY0 %u\n", hex_ctrl->otf_key[0]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CNT3 %u\n", hex_ctrl->otf_cnt[3]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CNT2 %u\n", hex_ctrl->otf_cnt[2]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CNT1 %u\n", hex_ctrl->otf_cnt[1]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_CNT0 %u\n", hex_ctrl->otf_cnt[0]);
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_OTF_STREAM_CNT %u\n",
+ hex_ctrl->otf_stream_cnt);
+
+ print_tsmux(TSMUX_SFR, "TSMUX_HEX_DBG_CTRL_BYPASS %d\n",
+ hex_ctrl->dbg_ctrl_bypass);
+#endif
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_src_addr(struct tsmux_device *tsmux_dev,
+ struct tsmux_buffer_info *buf_info)
+{
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || buf_info == NULL)
+ return;
+
+ TSMUX_WRITEL(buf_info->dma_addr, TSMUX_SRC_BASE_ADDR);
+ print_tsmux(TSMUX_SFR, "src_addr 0x%llx\n", buf_info->dma_addr);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_src_len(struct tsmux_device *tsmux_dev, int src_len)
+{
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ TSMUX_WRITEL(src_len, TSMUX_SRC_LEN_ADDR);
+ print_tsmux(TSMUX_SFR, "src_len %d\n", src_len);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_dst_addr(struct tsmux_device *tsmux_dev,
+ struct tsmux_buffer_info *buf_info)
+{
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL || buf_info == NULL)
+ return;
+
+ TSMUX_WRITEL(buf_info->dma_addr, TSMUX_DST_BASE_ADDR);
+ print_tsmux(TSMUX_SFR, "dst_addr 0x%llx\n", buf_info->dma_addr);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_job_queue_pkt_ctrl(struct tsmux_device *tsmux_dev)
+{
+ int total_udelay;
+ u32 pkt_ctrl_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ /* set pkt_ctrl_reg */
+ pkt_ctrl_reg = TSMUX_READL(TSMUX_PKT_CTRL_ADDR);
+ total_udelay = 0;
+ while ((pkt_ctrl_reg & TSMUX_PKT_CTRL_ENQUEUE_MASK) &&
+ total_udelay < 1000) {
+ udelay(100);
+ total_udelay += 100;
+ }
+
+ tsmux_print_tsmux_sfr(tsmux_dev);
+ tsmux_print_dbg_info_all(tsmux_dev);
+
+ pkt_ctrl_reg &= ~(TSMUX_PKT_CTRL_ENQUEUE_MASK);
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_ENQUEUE_MASK *
+ (1 << TSMUX_PKT_CTRL_ENQUEUE_SHIFT);
+ TSMUX_WRITEL(pkt_ctrl_reg, TSMUX_PKT_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "write pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_reset_pkt_ctrl(struct tsmux_device *tsmux_dev)
+{
+ u32 pkt_ctrl_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ pkt_ctrl_reg = TSMUX_READL(TSMUX_PKT_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "read pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ pkt_ctrl_reg |= TSMUX_PKT_CTRL_SW_RESET_MASK &
+ (1 << TSMUX_PKT_CTRL_SW_RESET_SHIFT);
+ TSMUX_WRITEL(pkt_ctrl_reg, TSMUX_PKT_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "TSMUX_PKT_CTRL_SW_RESET\n");
+ print_tsmux(TSMUX_SFR, "write pkt_ctrl_reg 0x%x\n", pkt_ctrl_reg);
+
+ /* default is CONSECUTIVE mode */
+ TSMUX_WRITEL(TSMUX_CMD_CTRL_RESET_VALUE, TSMUX_CMD_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "write cmd_ctrl_reg 0x%x\n",
+ TSMUX_CMD_CTRL_RESET_VALUE);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_enable_int_job_done(struct tsmux_device *tsmux_dev)
+{
+ u32 int_en_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ /* enable interrupt */
+ int_en_reg = TSMUX_READL(TSMUX_INT_EN_ADDR);
+ int_en_reg |= TSMUX_INT_EN_JOB_DONE;
+ TSMUX_WRITEL(int_en_reg, TSMUX_INT_EN_ADDR);
+ print_tsmux(TSMUX_SFR, "write int_en_reg 0x%x\n", int_en_reg);
+ int_en_reg = TSMUX_READL(TSMUX_INT_EN_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_en_reg 0x%x\n", int_en_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_disable_int_job_done(struct tsmux_device *tsmux_dev)
+{
+ u32 int_en_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ /* enable interrupt */
+ int_en_reg = TSMUX_READL(TSMUX_INT_EN_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_en_reg 0x%x\n", int_en_reg);
+
+ int_en_reg &= ~(TSMUX_INT_EN_JOB_DONE);
+ TSMUX_WRITEL(int_en_reg, TSMUX_INT_EN_ADDR);
+ print_tsmux(TSMUX_SFR, "write int_en_reg 0x%x\n", int_en_reg);
+ int_en_reg = TSMUX_READL(TSMUX_INT_EN_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_en_reg 0x%x\n", int_en_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+void tsmux_set_cmd_ctrl(struct tsmux_device *tsmux_dev, int mode)
+{
+ u32 cmd_ctrl_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ cmd_ctrl_reg = TSMUX_READL(TSMUX_CMD_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "read cmd_ctrl_reg 0x%x\n", cmd_ctrl_reg);
+
+ cmd_ctrl_reg = TSMUX_CMD_CTRL_MODE_MASK &
+ (mode << TSMUX_CMD_CTRL_MODE_SHIFT);
+ TSMUX_WRITEL(cmd_ctrl_reg, TSMUX_CMD_CTRL_ADDR);
+ print_tsmux(TSMUX_SFR, "write cmd_ctrl_reg 0x%x\n", cmd_ctrl_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+bool tsmux_is_job_done_id_0(struct tsmux_device *tsmux_dev)
+{
+ u32 int_stat_reg;
+ bool ret = false;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return ret;
+
+ int_stat_reg = TSMUX_READL(TSMUX_INT_STAT_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_stat_reg 0x%x\n", int_stat_reg);
+
+ if (int_stat_reg & TSMUX_INT_STAT_JOB_ID_0_DONE)
+ ret = true;
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+
+ return ret;
+}
+
+bool tsmux_is_job_done_id_1(struct tsmux_device *tsmux_dev)
+{
+ u32 int_stat_reg;
+ bool ret = false;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return ret;
+
+ int_stat_reg = TSMUX_READL(TSMUX_INT_STAT_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_stat_reg 0x%x\n", int_stat_reg);
+
+ if (int_stat_reg & TSMUX_INT_STAT_JOB_ID_1_DONE)
+ ret = true;
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+
+ return ret;
+}
+
+bool tsmux_is_job_done_id_2(struct tsmux_device *tsmux_dev)
+{
+ u32 int_stat_reg;
+ bool ret = false;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return ret;
+
+ int_stat_reg = TSMUX_READL(TSMUX_INT_STAT_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_stat_reg 0x%x\n", int_stat_reg);
+
+ if (int_stat_reg & TSMUX_INT_STAT_JOB_ID_2_DONE)
+ ret = true;
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+
+ return ret;
+
+}
+
+bool tsmux_is_job_done_id_3(struct tsmux_device *tsmux_dev)
+{
+ u32 int_stat_reg;
+ bool ret = false;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return false;
+
+ int_stat_reg = TSMUX_READL(TSMUX_INT_STAT_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_stat_reg 0x%x\n", int_stat_reg);
+
+ if (int_stat_reg & TSMUX_INT_STAT_JOB_ID_3_DONE)
+ ret = true;
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+
+ return ret;
+}
+
+void tsmux_clear_job_done(struct tsmux_device *tsmux_dev, int job_id)
+{
+ u32 int_stat_reg;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return;
+
+ int_stat_reg = TSMUX_INT_STAT_JOB_DONE_MASK & (1 << job_id);
+ TSMUX_WRITEL(int_stat_reg, TSMUX_INT_STAT_ADDR);
+ int_stat_reg = TSMUX_READL(TSMUX_INT_STAT_ADDR);
+ print_tsmux(TSMUX_SFR, "read int_stat_reg 0x%x\n", int_stat_reg);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+}
+
+int tsmux_get_dst_len(struct tsmux_device *tsmux_dev, int job_id)
+{
+ u32 dst_len_reg = 0;
+
+ print_tsmux(TSMUX_SFR, "%s++\n", __func__);
+
+ if (tsmux_dev == NULL)
+ return dst_len_reg;
+
+ dst_len_reg = TSMUX_READL(TSMUX_DST_LEN0_ADDR + job_id * 4);
+ print_tsmux(TSMUX_SFR, "read dst_len_reg 0x%x, job_id %d\n",
+ dst_len_reg, job_id);
+
+ print_tsmux(TSMUX_SFR, "%s--\n", __func__);
+
+ return dst_len_reg;
+}
--- /dev/null
+/*
+ * copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Core file for Samsung EXYNOS TSMUX driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef TSMUX_REG_H
+#define TSMUX_REG_H
+
+#include <linux/kernel.h>
+
+#include "tsmux_dev.h"
+
+//#define ASB_WORK
+
+void tsmux_print_dbg_info_all(struct tsmux_device *tsmux_dev);
+
+void tsmux_print_tsmux_sfr(struct tsmux_device *tsmux_dev);
+
+void tsmux_set_psi_info(struct tsmux_device *tsmux_dev,
+ struct tsmux_psi_info *psi_info);
+
+void tsmux_set_pkt_ctrl(struct tsmux_device *tsmux_dev,
+ struct tsmux_pkt_ctrl *pkt_ctrl);
+
+void tsmux_set_pes_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_pes_hdr *pes_hdr);
+
+void tsmux_set_ts_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_ts_hdr *ts_hdr);
+
+void tsmux_set_rtp_hdr(struct tsmux_device *tsmux_dev,
+ struct tsmux_rtp_hdr *rtp_hdr);
+
+void tsmux_set_swp_ctrl(struct tsmux_device *tsmux_dev,
+ struct tsmux_swp_ctrl *swp_ctrl);
+
+void tsmux_clear_hex_ctrl(void);
+
+void tsmux_set_hex_ctrl(struct tsmux_context *ctx,
+ struct tsmux_hex_ctrl *hex_ctrl);
+
+void tsmux_set_src_addr(struct tsmux_device *tsmux_dev,
+ struct tsmux_buffer_info *buf_info);
+
+void tsmux_set_src_len(struct tsmux_device *tsmux_dev, int src_len);
+
+void tsmux_set_dst_addr(struct tsmux_device *tsmux_dev,
+ struct tsmux_buffer_info *buf_info);
+
+void tsmux_job_queue_pkt_ctrl(struct tsmux_device *tsmux_dev);
+
+void tsmux_reset_pkt_ctrl(struct tsmux_device *tsmux_dev);
+
+void tsmux_enable_int_job_done(struct tsmux_device *tsmux_dev);
+void tsmux_disable_int_job_done(struct tsmux_device *tsmux_dev);
+
+void tsmux_set_cmd_ctrl(struct tsmux_device *tsmux_dev, int mode);
+
+bool tsmux_is_job_done_id_0(struct tsmux_device *tsmux_dev);
+bool tsmux_is_job_done_id_1(struct tsmux_device *tsmux_dev);
+bool tsmux_is_job_done_id_2(struct tsmux_device *tsmux_dev);
+bool tsmux_is_job_done_id_3(struct tsmux_device *tsmux_dev);
+
+void tsmux_clear_job_done(struct tsmux_device *tsmux_dev, int job_id);
+
+int tsmux_get_dst_len(struct tsmux_device *tsmux_dev, int job_id);
+
+#endif