From: shinwon.lee Date: Fri, 20 Jul 2018 09:49:13 +0000 (+0900) Subject: media: tsmux: init version X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=ae5421ce0b617c798d8ca03e006812fae21c57cf;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git media: tsmux: init version Change-Id: I482433ad032068c39884d12b71a80e804bc8f81b Signed-off-by: shinwon.lee --- diff --git a/drivers/media/platform/exynos/tsmux/Kconfig b/drivers/media/platform/exynos/tsmux/Kconfig new file mode 100644 index 000000000000..ac582d0cb03b --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/Kconfig @@ -0,0 +1,10 @@ +# +# Exynos tsmux device driver +# + +config VIDEO_EXYNOS_TSMUX + bool "EXYNOS TSMUX Driver" + depends on VIDEO_EXYNOS + default n + ---help--- + Repeater driver for WFD diff --git a/drivers/media/platform/exynos/tsmux/Makefile b/drivers/media/platform/exynos/tsmux/Makefile new file mode 100644 index 000000000000..0ac374233927 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/Makefile @@ -0,0 +1,9 @@ +# +# 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 diff --git a/drivers/media/platform/exynos/tsmux/tsmux.h b/drivers/media/platform/exynos/tsmux/tsmux.h new file mode 100644 index 000000000000..546cc87827b6 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux.h @@ -0,0 +1,196 @@ +/* + * 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 */ diff --git a/drivers/media/platform/exynos/tsmux/tsmux_dbg.h b/drivers/media/platform/exynos/tsmux/tsmux_dbg.h new file mode 100644 index 000000000000..740b7ff4b12e --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux_dbg.h @@ -0,0 +1,30 @@ +/* + * 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 diff --git a/drivers/media/platform/exynos/tsmux/tsmux_dev.c b/drivers/media/platform/exynos/tsmux/tsmux_dev.c new file mode 100644 index 000000000000..9c20ca6350a7 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux_dev.c @@ -0,0 +1,1509 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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 "); +MODULE_DESCRIPTION("EXYNOS tsmux driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/exynos/tsmux/tsmux_dev.h b/drivers/media/platform/exynos/tsmux/tsmux_dev.h new file mode 100644 index 000000000000..175cd0953705 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux_dev.h @@ -0,0 +1,104 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 */ diff --git a/drivers/media/platform/exynos/tsmux/tsmux_reg.c b/drivers/media/platform/exynos/tsmux/tsmux_reg.c new file mode 100644 index 000000000000..0444cd91bef2 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux_reg.c @@ -0,0 +1,1042 @@ +/* + * 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 +#include + +#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 +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; +} diff --git a/drivers/media/platform/exynos/tsmux/tsmux_reg.h b/drivers/media/platform/exynos/tsmux/tsmux_reg.h new file mode 100644 index 000000000000..277213dc0612 --- /dev/null +++ b/drivers/media/platform/exynos/tsmux/tsmux_reg.h @@ -0,0 +1,74 @@ +/* + * 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 + +#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