cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

s5p_mfc_ctrl.c (12010B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
      4 *
      5 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
      6 *		http://www.samsung.com/
      7 */
      8
      9#include <linux/delay.h>
     10#include <linux/err.h>
     11#include <linux/firmware.h>
     12#include <linux/jiffies.h>
     13#include <linux/sched.h>
     14#include "s5p_mfc_cmd.h"
     15#include "s5p_mfc_common.h"
     16#include "s5p_mfc_debug.h"
     17#include "s5p_mfc_intr.h"
     18#include "s5p_mfc_opr.h"
     19#include "s5p_mfc_pm.h"
     20#include "s5p_mfc_ctrl.h"
     21
     22/* Allocate memory for firmware */
     23int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
     24{
     25	struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf;
     26	int err;
     27
     28	fw_buf->size = dev->variant->buf_size->fw;
     29
     30	if (fw_buf->virt) {
     31		mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
     32		return -ENOMEM;
     33	}
     34
     35	err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf);
     36	if (err) {
     37		mfc_err("Allocating bitprocessor buffer failed\n");
     38		return err;
     39	}
     40
     41	return 0;
     42}
     43
     44/* Load firmware */
     45int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
     46{
     47	struct firmware *fw_blob;
     48	int i, err = -EINVAL;
     49
     50	/* Firmware has to be present as a separate file or compiled
     51	 * into kernel. */
     52	mfc_debug_enter();
     53
     54	if (dev->fw_get_done)
     55		return 0;
     56
     57	for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) {
     58		if (!dev->variant->fw_name[i])
     59			continue;
     60		err = request_firmware((const struct firmware **)&fw_blob,
     61				dev->variant->fw_name[i], &dev->plat_dev->dev);
     62		if (!err) {
     63			dev->fw_ver = (enum s5p_mfc_fw_ver) i;
     64			break;
     65		}
     66	}
     67
     68	if (err != 0) {
     69		mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
     70		return -EINVAL;
     71	}
     72	if (fw_blob->size > dev->fw_buf.size) {
     73		mfc_err("MFC firmware is too big to be loaded\n");
     74		release_firmware(fw_blob);
     75		return -ENOMEM;
     76	}
     77	memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size);
     78	wmb();
     79	dev->fw_get_done = true;
     80	release_firmware(fw_blob);
     81	mfc_debug_leave();
     82	return 0;
     83}
     84
     85/* Release firmware memory */
     86int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
     87{
     88	/* Before calling this function one has to make sure
     89	 * that MFC is no longer processing */
     90	s5p_mfc_release_priv_buf(dev, &dev->fw_buf);
     91	dev->fw_get_done = false;
     92	return 0;
     93}
     94
     95static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev)
     96{
     97	unsigned int status;
     98	unsigned long timeout;
     99
    100	/* Reset */
    101	mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
    102	timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
    103	/* Check bus status */
    104	do {
    105		if (time_after(jiffies, timeout)) {
    106			mfc_err("Timeout while resetting MFC.\n");
    107			return -EIO;
    108		}
    109		status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
    110	} while ((status & 0x2) == 0);
    111	return 0;
    112}
    113
    114/* Reset the device */
    115int s5p_mfc_reset(struct s5p_mfc_dev *dev)
    116{
    117	unsigned int mc_status;
    118	unsigned long timeout;
    119	int i;
    120
    121	mfc_debug_enter();
    122
    123	if (IS_MFCV6_PLUS(dev)) {
    124		/* Zero Initialization of MFC registers */
    125		mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
    126		mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6);
    127		mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6);
    128
    129		for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
    130			mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
    131
    132		/* check bus reset control before reset */
    133		if (dev->risc_on)
    134			if (s5p_mfc_bus_reset(dev))
    135				return -EIO;
    136		/* Reset
    137		 * set RISC_ON to 0 during power_on & wake_up.
    138		 * V6 needs RISC_ON set to 0 during reset also.
    139		 */
    140		if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev)))
    141			mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
    142
    143		mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6);
    144		mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6);
    145	} else {
    146		/* Stop procedure */
    147		/*  reset RISC */
    148		mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
    149		/*  All reset except for MC */
    150		mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
    151		mdelay(10);
    152
    153		timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
    154		/* Check MC status */
    155		do {
    156			if (time_after(jiffies, timeout)) {
    157				mfc_err("Timeout while resetting MFC\n");
    158				return -EIO;
    159			}
    160
    161			mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
    162
    163		} while (mc_status & 0x3);
    164
    165		mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
    166		mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
    167	}
    168
    169	mfc_debug_leave();
    170	return 0;
    171}
    172
    173static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
    174{
    175	if (IS_MFCV6_PLUS(dev)) {
    176		mfc_write(dev, dev->dma_base[BANK_L_CTX],
    177			  S5P_FIMV_RISC_BASE_ADDRESS_V6);
    178		mfc_debug(2, "Base Address : %pad\n",
    179			  &dev->dma_base[BANK_L_CTX]);
    180	} else {
    181		mfc_write(dev, dev->dma_base[BANK_L_CTX],
    182			  S5P_FIMV_MC_DRAMBASE_ADR_A);
    183		mfc_write(dev, dev->dma_base[BANK_R_CTX],
    184			  S5P_FIMV_MC_DRAMBASE_ADR_B);
    185		mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
    186			  &dev->dma_base[BANK_L_CTX],
    187			  &dev->dma_base[BANK_R_CTX]);
    188	}
    189}
    190
    191static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
    192{
    193	if (IS_MFCV6_PLUS(dev)) {
    194		/* Zero initialization should be done before RESET.
    195		 * Nothing to do here. */
    196	} else {
    197		mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
    198		mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
    199		mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
    200		mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
    201	}
    202}
    203
    204/* Initialize hardware */
    205int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
    206{
    207	unsigned int ver;
    208	int ret;
    209
    210	mfc_debug_enter();
    211	if (!dev->fw_buf.virt) {
    212		mfc_err("Firmware memory is not allocated.\n");
    213		return -EINVAL;
    214	}
    215
    216	/* 0. MFC reset */
    217	mfc_debug(2, "MFC reset..\n");
    218	s5p_mfc_clock_on();
    219	dev->risc_on = 0;
    220	ret = s5p_mfc_reset(dev);
    221	if (ret) {
    222		mfc_err("Failed to reset MFC - timeout\n");
    223		return ret;
    224	}
    225	mfc_debug(2, "Done MFC reset..\n");
    226	/* 1. Set DRAM base Addr */
    227	s5p_mfc_init_memctrl(dev);
    228	/* 2. Initialize registers of channel I/F */
    229	s5p_mfc_clear_cmds(dev);
    230	/* 3. Release reset signal to the RISC */
    231	s5p_mfc_clean_dev_int_flags(dev);
    232	if (IS_MFCV6_PLUS(dev)) {
    233		dev->risc_on = 1;
    234		mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
    235	}
    236	else
    237		mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
    238
    239	if (IS_MFCV10(dev))
    240		mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10);
    241
    242	mfc_debug(2, "Will now wait for completion of firmware transfer\n");
    243	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
    244		mfc_err("Failed to load firmware\n");
    245		s5p_mfc_reset(dev);
    246		s5p_mfc_clock_off();
    247		return -EIO;
    248	}
    249	s5p_mfc_clean_dev_int_flags(dev);
    250	/* 4. Initialize firmware */
    251	ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev);
    252	if (ret) {
    253		mfc_err("Failed to send command to MFC - timeout\n");
    254		s5p_mfc_reset(dev);
    255		s5p_mfc_clock_off();
    256		return ret;
    257	}
    258	mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
    259	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
    260		mfc_err("Failed to init hardware\n");
    261		s5p_mfc_reset(dev);
    262		s5p_mfc_clock_off();
    263		return -EIO;
    264	}
    265	dev->int_cond = 0;
    266	if (dev->int_err != 0 || dev->int_type !=
    267					S5P_MFC_R2H_CMD_SYS_INIT_RET) {
    268		/* Failure. */
    269		mfc_err("Failed to init firmware - error: %d int: %d\n",
    270						dev->int_err, dev->int_type);
    271		s5p_mfc_reset(dev);
    272		s5p_mfc_clock_off();
    273		return -EIO;
    274	}
    275	if (IS_MFCV6_PLUS(dev))
    276		ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6);
    277	else
    278		ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
    279
    280	mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
    281		(ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
    282	s5p_mfc_clock_off();
    283	mfc_debug_leave();
    284	return 0;
    285}
    286
    287
    288/* Deinitialize hardware */
    289void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
    290{
    291	s5p_mfc_clock_on();
    292
    293	s5p_mfc_reset(dev);
    294	s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
    295
    296	s5p_mfc_clock_off();
    297}
    298
    299int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
    300{
    301	int ret;
    302
    303	mfc_debug_enter();
    304	s5p_mfc_clock_on();
    305	s5p_mfc_clean_dev_int_flags(dev);
    306	ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev);
    307	if (ret) {
    308		mfc_err("Failed to send command to MFC - timeout\n");
    309		return ret;
    310	}
    311	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) {
    312		mfc_err("Failed to sleep\n");
    313		return -EIO;
    314	}
    315	s5p_mfc_clock_off();
    316	dev->int_cond = 0;
    317	if (dev->int_err != 0 || dev->int_type !=
    318						S5P_MFC_R2H_CMD_SLEEP_RET) {
    319		/* Failure. */
    320		mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
    321								dev->int_type);
    322		return -EIO;
    323	}
    324	mfc_debug_leave();
    325	return ret;
    326}
    327
    328static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev)
    329{
    330	int ret;
    331
    332	/* Release reset signal to the RISC */
    333	dev->risc_on = 1;
    334	mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
    335
    336	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
    337		mfc_err("Failed to reset MFCV8\n");
    338		return -EIO;
    339	}
    340	mfc_debug(2, "Write command to wakeup MFCV8\n");
    341	ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
    342	if (ret) {
    343		mfc_err("Failed to send command to MFCV8 - timeout\n");
    344		return ret;
    345	}
    346
    347	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
    348		mfc_err("Failed to wakeup MFC\n");
    349		return -EIO;
    350	}
    351	return ret;
    352}
    353
    354static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev)
    355{
    356	int ret;
    357
    358	/* Send MFC wakeup command */
    359	ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
    360	if (ret) {
    361		mfc_err("Failed to send command to MFC - timeout\n");
    362		return ret;
    363	}
    364
    365	/* Release reset signal to the RISC */
    366	if (IS_MFCV6_PLUS(dev)) {
    367		dev->risc_on = 1;
    368		mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
    369	} else {
    370		mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
    371	}
    372
    373	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
    374		mfc_err("Failed to wakeup MFC\n");
    375		return -EIO;
    376	}
    377	return ret;
    378}
    379
    380int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
    381{
    382	int ret;
    383
    384	mfc_debug_enter();
    385	/* 0. MFC reset */
    386	mfc_debug(2, "MFC reset..\n");
    387	s5p_mfc_clock_on();
    388	dev->risc_on = 0;
    389	ret = s5p_mfc_reset(dev);
    390	if (ret) {
    391		mfc_err("Failed to reset MFC - timeout\n");
    392		s5p_mfc_clock_off();
    393		return ret;
    394	}
    395	mfc_debug(2, "Done MFC reset..\n");
    396	/* 1. Set DRAM base Addr */
    397	s5p_mfc_init_memctrl(dev);
    398	/* 2. Initialize registers of channel I/F */
    399	s5p_mfc_clear_cmds(dev);
    400	s5p_mfc_clean_dev_int_flags(dev);
    401	/* 3. Send MFC wakeup command and wait for completion*/
    402	if (IS_MFCV8_PLUS(dev))
    403		ret = s5p_mfc_v8_wait_wakeup(dev);
    404	else
    405		ret = s5p_mfc_wait_wakeup(dev);
    406
    407	s5p_mfc_clock_off();
    408	if (ret)
    409		return ret;
    410
    411	dev->int_cond = 0;
    412	if (dev->int_err != 0 || dev->int_type !=
    413						S5P_MFC_R2H_CMD_WAKEUP_RET) {
    414		/* Failure. */
    415		mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
    416								dev->int_type);
    417		return -EIO;
    418	}
    419	mfc_debug_leave();
    420	return 0;
    421}
    422
    423int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
    424{
    425	int ret = 0;
    426
    427	ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx);
    428	if (ret) {
    429		mfc_err("Failed allocating instance buffer\n");
    430		goto err;
    431	}
    432
    433	if (ctx->type == MFCINST_DECODER) {
    434		ret = s5p_mfc_hw_call(dev->mfc_ops,
    435					alloc_dec_temp_buffers, ctx);
    436		if (ret) {
    437			mfc_err("Failed allocating temporary buffers\n");
    438			goto err_free_inst_buf;
    439		}
    440	}
    441
    442	set_work_bit_irqsave(ctx);
    443	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
    444	if (s5p_mfc_wait_for_done_ctx(ctx,
    445		S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
    446		/* Error or timeout */
    447		mfc_err("Error getting instance from hardware\n");
    448		ret = -EIO;
    449		goto err_free_desc_buf;
    450	}
    451
    452	mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
    453	return ret;
    454
    455err_free_desc_buf:
    456	if (ctx->type == MFCINST_DECODER)
    457		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
    458err_free_inst_buf:
    459	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
    460err:
    461	return ret;
    462}
    463
    464void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
    465{
    466	ctx->state = MFCINST_RETURN_INST;
    467	set_work_bit_irqsave(ctx);
    468	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
    469	/* Wait until instance is returned or timeout occurred */
    470	if (s5p_mfc_wait_for_done_ctx(ctx,
    471				S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
    472		mfc_err("Err returning instance\n");
    473
    474	/* Free resources */
    475	s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
    476	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
    477	if (ctx->type == MFCINST_DECODER)
    478		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
    479
    480	ctx->inst_no = MFC_NO_INSTANCE_SET;
    481	ctx->state = MFCINST_FREE;
    482}