rt-thread/bsp/phytium/libraries/standalone/drivers/pcie/fpcie/fpcie_ep.c

228 lines
7.1 KiB
C
Raw Normal View History

/*
* Copyright : (C) 2022 Phytium Information Technology, Inc.
* All Rights Reserved.
*
* This program is OPEN SOURCE software: you can redistribute it and/or modify it
* under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
* either version 1.0 of the License, or (at your option) any later version.
*
* 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 Phytium Public License for more details.
*
*
* FilePath: fpcie_ep.c
* Date: 2022-08-10 14:55:11
* LastEditTime: 2022-08-18 08:57:59
* Description: This file is for pcie endpoint device operation.
*
* Modify History:
* Ver   Who        Date         Changes
* ----- ------     --------    --------------------------------------
* 1.0 huanghe 2022/8/18 init commit
*/
#include "fpcie.h"
#include "fpcie_hw.h"
#include "ftypes.h"
#include "fpcie_common.h"
#include <math.h>
#include <string.h>
#include "fkernel.h"
#include "fdebug.h"
/***************************** Include Files *********************************/
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/************************** Variable Definitions *****************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define FPCIE_EP_DEBUG_TAG "FPCIE_EP"
#define FPCIE_EP_ERROR(format, ...) FT_DEBUG_PRINT_E(FPCIE_EP_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_EP_DEBUG_I(format, ...) FT_DEBUG_PRINT_I(FPCIE_EP_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_EP_DEBUG_W(format, ...) FT_DEBUG_PRINT_W(FPCIE_EP_DEBUG_TAG, format, ##__VA_ARGS__)
#define FPCIE_EP_DEBUG_E(format, ...) FT_DEBUG_PRINT_E(FPCIE_EP_DEBUG_TAG, format, ##__VA_ARGS__)
/************************** Function Prototypes ******************************/
int FPcieEpSetBar(FPcie *instance_p, u32 peu_num, u32 bar_num, u64 bar_mem_addr, u64 bar_mem_size, int flags)
{
u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
u64 sz;
uintptr_t base_addr;
FASSERT(instance_p != NULL);
base_addr = *(uintptr_t *)(&instance_p->config.control_c0_address + peu_num);
/* BAR size is 2^(aperture + 7) */
sz = max(bar_mem_size, (u64)FPCIE_EP_MIN_APERTURE);
/*
* roundup_pow_of_two() returns an unsigned long, which is not suited
* for 64bit values.
*/
sz = 1ULL << fls(sz - 1);
aperture = log2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
if ((flags & FPCIE_BASE_ADDRESS_SPACE) == FPCIE_BASE_ADDRESS_SPACE)
{
ctrl = FPCIE_LM_BAR_CFG_CTRL_IO_32BITS;
}
else
{
boolean is_prefetch = !!(flags & FPCIE_BASE_ADDRESS_MEM_PREFETCH);
boolean is_64bits = sz > SZ_2G;
if (is_64bits && (bar_num & 1))
{
return FPCIE_ERR_INVALID_PARAM;
}
if (is_64bits && !(flags & FPCIE_BASE_ADDRESS_MEM_TYPE_64))
{
flags |= FPCIE_BASE_ADDRESS_MEM_TYPE_64;
}
if (is_64bits && is_prefetch)
{
ctrl = FPCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
}
else if (is_prefetch)
{
ctrl = FPCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
}
else if (is_64bits)
{
ctrl = FPCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
}
else
{
ctrl = FPCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
}
}
addr0 = LOWER_32_BITS(bar_mem_addr);
addr1 = UPPER_32_BITS(bar_mem_addr);
FPCIE_WRITEREG(base_addr, FPCIE_AT_IB_EP_FUNC_BAR_ADDR0(0, bar_num), addr0);
FPCIE_WRITEREG(base_addr, FPCIE_AT_IB_EP_FUNC_BAR_ADDR1(0, bar_num), addr1);
if (bar_num < FPCIE_BAR_4)
{
reg = FPCIE_LM_EP_FUNC_BAR_CFG0(0);
b = reg;
}
else
{
reg = FPCIE_LM_EP_FUNC_BAR_CFG0(0);
b = reg - FPCIE_BAR_4;
}
cfg = FPCIE_READREG(base_addr, reg);
cfg &= ~(FPCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
FPCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
cfg |= (FPCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
FPCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
FPCIE_WRITEREG(base_addr, reg, cfg);
return FT_SUCCESS;
}
int FPcieEpCleanBar(FPcie *instance_p, u32 peu_num, u32 bar_num)
{
u32 reg, cfg, b, ctrl;
uintptr_t base_addr;
base_addr = *(uintptr_t *)(&instance_p->config.control_c0_address + peu_num);
if (bar_num < FPCIE_BAR_4)
{
reg = FPCIE_LM_EP_FUNC_BAR_CFG0(0);
b = bar_num;
}
else
{
reg = FPCIE_LM_EP_FUNC_BAR_CFG1(0);
b = bar_num - FPCIE_BAR_4;
}
ctrl = FPCIE_LM_BAR_CFG_CTRL_DISABLED;
cfg = FPCIE_READREG(base_addr, reg);
cfg &= ~(FPCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
FPCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
cfg |= FPCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
FPCIE_WRITEREG(base_addr, reg, cfg);
return FT_SUCCESS;
}
static int GetOneInData(u64 data)
{
int n = 63;
while (!(data & GENMASK_ULL(63, 63)))
{
n--;
data <<= 1;
}
return n;
}
int FPcieEpMapAddr(FPcie *instance_p, u32 peu_num, u64 phy_addr, u64 pcie_addr, u64 size)
{
u32 addr0, addr1;
u64 pcie_addr_limit;
u64 reg;
uintptr_t config_address;
uintptr_t control_address;
FASSERT(instance_p != NULL);
if (peu_num < FPCIE_PEU1_C0)
{
config_address = instance_p->config.peu0_config_address;
}
else
{
config_address = instance_p->config.peu1_config_address;
}
control_address = *(uintptr_t *)(&instance_p->config.control_c0_address + peu_num);
pcie_addr_limit = pcie_addr + size;
if (phy_addr < 0x1000000000)
{
addr0 = ((pcie_addr >> 16) & FPCIE_C0_PREF_BASE_MASK) | (pcie_addr_limit & FPCIE_C0_PREF_LIMIT_MASK);
reg = FPCIE_REG_EP_C0_PREF_BASE_LIMIT_OFFSET_GET(config_address, peu_num);
FPCIE_WRITEREG(reg, 0, addr0);
}
else
{
addr0 = (((pcie_addr & 0xFFFFFFFF) >> 15) & 0xFFF0) | (pcie_addr_limit & 0xFFF00000);
addr1 = ((pcie_addr >> 32) & 0xFF) | ((pcie_addr_limit >> 24) & 0xFF00);
reg = FPCIE_REG_EP_C0_MEM_BASE_LIMIT_OFFSET_GET(config_address, peu_num);
FPCIE_WRITEREG(reg, 0, addr0);
FPCIE_WRITEREG(reg + 4, 0, addr1);
}
addr0 = (phy_addr & 0xFFFFFF00) | (GetOneInData(size - 1) & 0x3F);
addr1 = (phy_addr >> 32);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_PATR0_OFFSET, addr0);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_PATR1_OFFSET, addr1);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_PHDR0_OFFSET, 2);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_PHDR1_OFFSET, 0);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_PHDR2_OFFSET, 0);
addr0 = (pcie_addr & 0xFFFFFF00) | (GetOneInData(size - 1) & 0x3F);
addr1 = (pcie_addr >> 32);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_ARBA0_OFFSET, addr0);
FPCIE_WRITEREG(control_address, FPCIE_REG_OUTBOUND_R0_ARBA1_OFFSET, addr1);
return FT_SUCCESS;
}