M7350/kernel/drivers/platform/msm/mhi/mhi_mmio_ops.c
2024-09-09 08:57:42 +00:00

252 lines
8.4 KiB
C

/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#include "mhi_sys.h"
#include "mhi_hwio.h"
#include "mhi.h"
enum MHI_STATUS mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt)
{
u32 pcie_word_val = 0;
u32 expiry_counter;
mhi_log(MHI_MSG_INFO, "Waiting for MMIO RESET bit to be cleared.\n");
pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr,
MHISTATUS);
MHI_READ_FIELD(pcie_word_val,
MHICTRL_RESET_MASK,
MHICTRL_RESET_SHIFT);
if (pcie_word_val == 0xFFFFFFFF)
return MHI_STATUS_LINK_DOWN;
while (MHI_STATE_RESET != pcie_word_val && expiry_counter < 100) {
expiry_counter++;
mhi_log(MHI_MSG_ERROR,
"Device is not RESET, sleeping and retrying.\n");
msleep(MHI_READY_STATUS_TIMEOUT_MS);
pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr,
MHICTRL);
MHI_READ_FIELD(pcie_word_val,
MHICTRL_RESET_MASK,
MHICTRL_RESET_SHIFT);
}
if (MHI_STATE_READY != pcie_word_val)
return MHI_STATUS_DEVICE_NOT_READY;
return MHI_STATUS_SUCCESS;
}
enum MHI_STATUS mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt)
{
u32 pcie_word_val = 0;
u32 expiry_counter;
mhi_log(MHI_MSG_INFO, "Waiting for MMIO Ready bit to be set\n");
/* Read MMIO and poll for READY bit to be set */
pcie_word_val = mhi_reg_read(
mhi_dev_ctxt->mmio_info.mmio_addr, MHISTATUS);
MHI_READ_FIELD(pcie_word_val,
MHISTATUS_READY_MASK,
MHISTATUS_READY_SHIFT);
if (pcie_word_val == 0xFFFFFFFF)
return MHI_STATUS_LINK_DOWN;
expiry_counter = 0;
while (MHI_STATE_READY != pcie_word_val && expiry_counter < 50) {
expiry_counter++;
mhi_log(MHI_MSG_ERROR,
"Device is not ready, sleeping and retrying.\n");
msleep(MHI_READY_STATUS_TIMEOUT_MS);
pcie_word_val = mhi_reg_read(mhi_dev_ctxt->mmio_info.mmio_addr,
MHISTATUS);
MHI_READ_FIELD(pcie_word_val,
MHISTATUS_READY_MASK, MHISTATUS_READY_SHIFT);
}
if (pcie_word_val != MHI_STATE_READY)
return MHI_STATUS_DEVICE_NOT_READY;
return MHI_STATUS_SUCCESS;
}
enum MHI_STATUS mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt)
{
u64 pcie_dword_val = 0;
u32 pcie_word_val = 0;
u32 i = 0;
enum MHI_STATUS ret_val;
mhi_log(MHI_MSG_INFO, "~~~ Initializing MMIO ~~~\n");
mhi_dev_ctxt->mmio_info.mmio_addr = mhi_dev_ctxt->dev_props->bar0_base;
mhi_log(MHI_MSG_INFO, "Bar 0 address is at: 0x%p\n",
mhi_dev_ctxt->mmio_info.mmio_addr);
mhi_dev_ctxt->mmio_info.mmio_len = mhi_reg_read(
mhi_dev_ctxt->mmio_info.mmio_addr,
MHIREGLEN);
if (0 == mhi_dev_ctxt->mmio_info.mmio_len) {
mhi_log(MHI_MSG_ERROR, "Received mmio length as zero\n");
return MHI_STATUS_ERROR;
}
mhi_log(MHI_MSG_INFO, "Testing MHI Ver\n");
mhi_dev_ctxt->dev_props->mhi_ver = mhi_reg_read(
mhi_dev_ctxt->mmio_info.mmio_addr, MHIVER);
if (MHI_VERSION != mhi_dev_ctxt->dev_props->mhi_ver) {
mhi_log(MHI_MSG_CRITICAL, "Bad MMIO version, 0x%x\n",
mhi_dev_ctxt->dev_props->mhi_ver);
if (mhi_dev_ctxt->dev_props->mhi_ver == 0xFFFFFFFF)
ret_val = mhi_wait_for_mdm(mhi_dev_ctxt);
if (ret_val)
return MHI_STATUS_ERROR;
}
/* Enable the channels */
for (i = 0; i < MHI_MAX_CHANNELS; ++i) {
struct mhi_chan_ctxt *chan_ctxt =
&mhi_dev_ctxt->dev_space.ring_ctxt.cc_list[i];
if (VALID_CHAN_NR(i))
chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_ENABLED;
else
chan_ctxt->mhi_chan_state = MHI_CHAN_STATE_DISABLED;
}
mhi_log(MHI_MSG_INFO,
"Read back MMIO Ready bit successfully. Moving on..\n");
mhi_log(MHI_MSG_INFO, "Reading channel doorbell offset\n");
mhi_dev_ctxt->mmio_info.chan_db_addr =
mhi_dev_ctxt->mmio_info.mmio_addr;
mhi_dev_ctxt->mmio_info.event_db_addr =
mhi_dev_ctxt->mmio_info.mmio_addr;
mhi_dev_ctxt->mmio_info.chan_db_addr += mhi_reg_read_field(
mhi_dev_ctxt->mmio_info.mmio_addr,
CHDBOFF, CHDBOFF_CHDBOFF_MASK,
CHDBOFF_CHDBOFF_SHIFT);
mhi_log(MHI_MSG_INFO, "Reading event doorbell offset\n");
mhi_dev_ctxt->mmio_info.event_db_addr += mhi_reg_read_field(
mhi_dev_ctxt->mmio_info.mmio_addr,
ERDBOFF, ERDBOFF_ERDBOFF_MASK,
ERDBOFF_ERDBOFF_SHIFT);
mhi_log(MHI_MSG_INFO, "Setting all MMIO values.\n");
mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr,
MHICFG,
MHICFG_NER_MASK, MHICFG_NER_SHIFT,
mhi_dev_ctxt->mmio_info.nr_event_rings);
pcie_dword_val = mhi_dev_ctxt->dev_space.ring_ctxt.dma_cc_list;
pcie_word_val = HIGH_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, CCABAP_HIGHER,
CCABAP_HIGHER_CCABAP_HIGHER_MASK,
CCABAP_HIGHER_CCABAP_HIGHER_SHIFT, pcie_word_val);
pcie_word_val = LOW_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr,
CCABAP_LOWER,
CCABAP_LOWER_CCABAP_LOWER_MASK,
CCABAP_LOWER_CCABAP_LOWER_SHIFT,
pcie_word_val);
/* Write the Event Context Base Address Register High and Low parts */
pcie_dword_val = mhi_dev_ctxt->dev_space.ring_ctxt.dma_ec_list;
pcie_word_val = HIGH_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, ECABAP_HIGHER,
ECABAP_HIGHER_ECABAP_HIGHER_MASK,
ECABAP_HIGHER_ECABAP_HIGHER_SHIFT, pcie_word_val);
pcie_word_val = LOW_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt, mhi_dev_ctxt->mmio_info.mmio_addr,
ECABAP_LOWER,
ECABAP_LOWER_ECABAP_LOWER_MASK,
ECABAP_LOWER_ECABAP_LOWER_SHIFT, pcie_word_val);
/* Write the Command Ring Control Register High and Low parts */
pcie_dword_val = mhi_dev_ctxt->dev_space.ring_ctxt.dma_cmd_ctxt;
pcie_word_val = HIGH_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr,
CRCBAP_HIGHER,
CRCBAP_HIGHER_CRCBAP_HIGHER_MASK,
CRCBAP_HIGHER_CRCBAP_HIGHER_SHIFT,
pcie_word_val);
pcie_word_val = LOW_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, CRCBAP_LOWER,
CRCBAP_LOWER_CRCBAP_LOWER_MASK,
CRCBAP_LOWER_CRCBAP_LOWER_SHIFT,
pcie_word_val);
mhi_dev_ctxt->mmio_info.cmd_db_addr =
mhi_dev_ctxt->mmio_info.mmio_addr + CRDB_LOWER;
/* Set the control and data segments device MMIO */
pcie_dword_val = mhi_dev_ctxt->dev_space.start_win_addr;
pcie_word_val = HIGH_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRLBASE_HIGHER,
MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_MASK,
MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_SHIFT,
pcie_word_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHIDATABASE_HIGHER,
MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_MASK,
MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_SHIFT,
pcie_word_val);
pcie_word_val = LOW_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRLBASE_LOWER,
MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_MASK,
MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_SHIFT,
pcie_word_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHIDATABASE_LOWER,
MHIDATABASE_LOWER_MHIDATABASE_LOWER_MASK,
MHIDATABASE_LOWER_MHIDATABASE_LOWER_SHIFT,
pcie_word_val);
pcie_dword_val = mhi_dev_ctxt->dev_space.end_win_addr;
pcie_word_val = HIGH_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRLLIMIT_HIGHER,
MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_MASK,
MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_SHIFT,
pcie_word_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHIDATALIMIT_HIGHER,
MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_MASK,
MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_SHIFT,
pcie_word_val);
pcie_word_val = LOW_WORD(pcie_dword_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr, MHICTRLLIMIT_LOWER,
MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_MASK,
MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_SHIFT,
pcie_word_val);
mhi_reg_write_field(mhi_dev_ctxt,
mhi_dev_ctxt->mmio_info.mmio_addr,
MHIDATALIMIT_LOWER,
MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_MASK,
MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_SHIFT,
pcie_word_val);
mhi_log(MHI_MSG_INFO, "Done..\n");
return MHI_STATUS_SUCCESS;
}