blob: ecb3b4f93f0d3d5a0fd7f125ad6627cc0536d7dc [file] [log] [blame]
/*
* Paintbox V1 specific MIPI support for Paintbox programmable IPU
*
* Copyright (C) 2017 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __PAINTBOX_MIPI_V1_H__
#define __PAINTBOX_MIPI_V1_H__
#include <linux/io.h>
#include "paintbox-common.h"
#include "paintbox-mipi.h"
#include "paintbox-regs.h"
#define MIPI_INVALID_FRAME_NUMBER -1
#define MIPI_INPUT_SOF_IMR (1 << 0)
#define MIPI_INPUT_SOF_ISR (1 << 0)
#define MIPI_INPUT_OVF_IMR (1 << 1)
#define MIPI_INPUT_OVF_ISR (1 << 1)
#define MIPI_OUTPUT_EOF_IMR (1 << 0)
#define MIPI_OUTPUT_EOF_ISR (1 << 0)
/* MIPI input streams 0..11 have a fixed mapping to DMA channels 0..11.
* MIPI output streams 0..3 and 4..7 share fixed mappings to DMA channels
* 12..15.
*/
#define MIPI_INPUT_DMA_CHANNEL_ID_START 0
#define MIPI_INPUT_DMA_CHANNEL_ID_END 11
#define MIPI_OUTPUT_DMA_CHANNEL_ID_START 12
#define MIPI_OUTPUT_DMA_CHANNEL_ID_END 15
static inline unsigned int mipi_stream_to_dma_channel_id(
struct paintbox_mipi_stream *stream)
{
return stream->is_input
? MIPI_INPUT_DMA_CHANNEL_ID_START + stream->stream_id
: MIPI_OUTPUT_DMA_CHANNEL_ID_START + (stream->stream_id % 4);
}
/* The caller to this function must hold pb->io_ipu.mipi_lock. */
static inline int mipi_output_clear_and_set_control(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t ctrl_clear_mask,
uint32_t ctrl_set_mask)
{
uint32_t ctrl;
ctrl = readl(pb->io_ipu.ipu_base + MPO_STRM_CTRL);
ctrl &= ~ctrl_clear_mask;
ctrl |= ctrl_set_mask;
writel(ctrl, pb->io_ipu.ipu_base + MPO_STRM_CTRL);
return 0;
}
/* The caller to the mipi_{in,out}put_(ack|{en,dis}able)_xxx functions must hold
* pb->io_ipu.mipi_lock.
*/
static inline int mipi_input_enable_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream)
{
writeq((MPI_CTRL_STRM_CONTINUOUS_SET0_MASK |
MPI_CTRL_STRM_ENA_SET0_MASK) << stream->stream_id,
pb->io_ipu.ipu_base + MPI_CTRL);
return 0;
}
static inline void mipi_input_set_imr(struct paintbox_data *pb,
uint32_t set_mask)
{
uint32_t val;
val = readl(pb->io_ipu.ipu_base + MPI_IMR);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPI_IMR);
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPI_IER);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPI_IER);
}
static inline void mipi_input_set_err_imr(struct paintbox_data *pb,
uint32_t set_mask)
{
uint32_t val;
val = readl(pb->io_ipu.ipu_base + MPI_ERR_IMR);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPI_ERR_IMR);
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPI_ERR_IER);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPI_ERR_IER);
}
static inline void mipi_input_clear_imr(struct paintbox_data *pb,
uint32_t clear_mask)
{
uint32_t val;
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPI_IER);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPI_IER);
val = readl(pb->io_ipu.ipu_base + MPI_IMR);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPI_IMR);
}
static inline void mipi_input_clear_err_imr(struct paintbox_data *pb,
uint32_t clear_mask)
{
uint32_t val;
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPI_ERR_IER);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPI_ERR_IER);
val = readl(pb->io_ipu.ipu_base + MPI_ERR_IMR);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPI_ERR_IMR);
}
static inline void mipi_output_set_imr(struct paintbox_data *pb,
uint32_t set_mask)
{
uint32_t val;
val = readl(pb->io_ipu.ipu_base + MPO_IMR);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPO_IMR);
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPO_IER);
val |= set_mask;
writel(val, pb->io_ipu.ipu_base + MPO_IER);
}
static inline void mipi_output_clear_imr(struct paintbox_data *pb,
uint32_t clear_mask)
{
uint32_t val;
/* With MIPI we enable and disable at the IER, as well as the IMR. */
val = readl(pb->io_ipu.ipu_base + MPO_IER);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPO_IER);
val = readl(pb->io_ipu.ipu_base + MPO_IMR);
val &= ~clear_mask;
writel(val, pb->io_ipu.ipu_base + MPO_IMR);
}
static inline int mipi_input_enable_irqs_and_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t imr_mask)
{
if (imr_mask & MIPI_INPUT_SOF_IMR)
mipi_input_set_imr(pb, 1 << (stream->stream_id +
MPI_IMR_SOF0_SHIFT));
if (imr_mask & MIPI_INPUT_OVF_IMR)
mipi_input_set_err_imr(pb, 1 << (stream->stream_id +
MPI_ERR_IMR_OVF0_SHIFT));
mipi_input_enable_stream(pb, stream);
return 0;
}
static inline int mipi_input_disable_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream)
{
writeq(MPI_CTRL_STRM_CONTINUOUS_CLR0_MASK << stream->stream_id,
pb->io_ipu.ipu_base + MPI_CTRL);
return 0;
}
static inline int mipi_input_disable_irqs_and_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t imr_mask)
{
if (imr_mask & MIPI_INPUT_SOF_IMR)
mipi_input_clear_imr(pb, 1 << (stream->stream_id +
MPI_IMR_SOF0_SHIFT));
if (imr_mask & MIPI_INPUT_OVF_IMR)
mipi_input_clear_err_imr(pb, 1 << (stream->stream_id +
MPI_ERR_IMR_OVF0_SHIFT));
mipi_input_disable_stream(pb, stream);
return 0;
}
static inline int mipi_output_ack_irqs(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t isr_mask)
{
if (isr_mask & MIPI_OUTPUT_EOF_ISR)
writel(1 << (stream->stream_id + MPO_ISR_EOF0_SHIFT),
pb->io_ipu.ipu_base + MPO_ISR);
return 0;
}
static inline int mipi_output_enable_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream)
{
writeq((MPO_CTRL_STRM_CONTINUOUS_SET0_MASK |
MPO_CTRL_STRM_ENA_SET0_MASK) << stream->stream_id,
pb->io_ipu.ipu_base + MPO_CTRL);
return 0;
}
static inline int mipi_output_enable_irqs_and_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t imr_mask,
bool row_sync)
{
uint32_t val;
if (imr_mask & MIPI_OUTPUT_EOF_IMR) {
val = readl(pb->io_ipu.ipu_base + MPO_IMR);
val |= 1 << (stream->stream_id + MPO_IMR_EOF0_SHIFT);
writel(val, pb->io_ipu.ipu_base + MPO_IMR);
}
paintbox_mipi_select_output_stream(pb, stream->stream_id);
/* {set,clear} RSYNC_EN in case previously {cleared,set} */
mipi_output_clear_and_set_control(pb, stream,
row_sync ? 0 : MPO_STRM_CTRL_RSYNC_EN_MASK,
row_sync ? MPO_STRM_CTRL_RSYNC_EN_MASK : 0);
mipi_output_enable_stream(pb, stream);
return 0;
}
static inline int mipi_output_disable_stream(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream)
{
writeq(MPO_CTRL_STRM_CONTINUOUS_CLR0_MASK << stream->stream_id,
pb->io_ipu.ipu_base + MPO_CTRL);
return 0;
}
static inline int mipi_output_disable_irqs(struct paintbox_data *pb,
struct paintbox_mipi_stream *stream, uint32_t imr_mask)
{
uint32_t val;
if (imr_mask & MIPI_OUTPUT_EOF_IMR) {
val = readl(pb->io_ipu.ipu_base + MPO_IMR);
val &= ~(1 << (stream->stream_id + MPO_IMR_EOF0_SHIFT));
writel(val, pb->io_ipu.ipu_base + MPO_IMR);
}
return 0;
}
#endif /* __PAINTBOX_MIPI_V1_H__ */