linux/drivers/memory/brcmstb_dpfe.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * DDR PHY Front End (DPFE) driver for Broadcom set top box SoCs
 *
 * Copyright (c) 2017 Broadcom
 */

/*
 * This driver provides access to the DPFE interface of Broadcom STB SoCs.
 * The firmware running on the DCPU inside the DDR PHY can provide current
 * information about the system's RAM, for instance the DRAM refresh rate.
 * This can be used as an indirect indicator for the DRAM's temperature.
 * Slower refresh rate means cooler RAM, higher refresh rate means hotter
 * RAM.
 *
 * Throughout the driver, we use readl_relaxed() and writel_relaxed(), which
 * already contain the appropriate le32_to_cpu()/cpu_to_le32() calls.
 *
 * Note regarding the loading of the firmware image: we use be32_to_cpu()
 * and le_32_to_cpu(), so we can support the following four cases:
 *     - LE kernel + LE firmware image (the most common case)
 *     - LE kernel + BE firmware image
 *     - BE kernel + LE firmware image
 *     - BE kernel + BE firmware image
 *
 * The DPCU always runs in big endian mode. The firmware image, however, can
 * be in either format. Also, communication between host CPU and DCPU is
 * always in little endian.
 */

#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>

#define DRVNAME

/* DCPU register offsets */
#define REG_DCPU_RESET
#define REG_TO_DCPU_MBOX
#define REG_TO_HOST_MBOX

/* Macros to process offsets returned by the DCPU */
#define DRAM_MSG_ADDR_OFFSET
#define DRAM_MSG_TYPE_OFFSET
#define DRAM_MSG_ADDR_MASK
#define DRAM_MSG_TYPE_MASK

/* Message RAM */
#define DCPU_MSG_RAM_START
#define DCPU_MSG_RAM(x)

/* DRAM Info Offsets & Masks */
#define DRAM_INFO_INTERVAL
#define DRAM_INFO_MR4
#define DRAM_INFO_ERROR
#define DRAM_INFO_MR4_MASK
#define DRAM_INFO_MR4_SHIFT

/* DRAM MR4 Offsets & Masks */
#define DRAM_MR4_REFRESH
#define DRAM_MR4_SR_ABORT
#define DRAM_MR4_PPRE
#define DRAM_MR4_TH_OFFS
#define DRAM_MR4_TUF

#define DRAM_MR4_REFRESH_MASK
#define DRAM_MR4_SR_ABORT_MASK
#define DRAM_MR4_PPRE_MASK
#define DRAM_MR4_TH_OFFS_MASK
#define DRAM_MR4_TUF_MASK

/* DRAM Vendor Offsets & Masks (API v2) */
#define DRAM_VENDOR_MR5
#define DRAM_VENDOR_MR6
#define DRAM_VENDOR_MR7
#define DRAM_VENDOR_MR8
#define DRAM_VENDOR_ERROR
#define DRAM_VENDOR_MASK
#define DRAM_VENDOR_SHIFT

/* DRAM Information Offsets & Masks (API v3) */
#define DRAM_DDR_INFO_MR4
#define DRAM_DDR_INFO_MR5
#define DRAM_DDR_INFO_MR6
#define DRAM_DDR_INFO_MR7
#define DRAM_DDR_INFO_MR8
#define DRAM_DDR_INFO_ERROR
#define DRAM_DDR_INFO_MASK

/* Reset register bits & masks */
#define DCPU_RESET_SHIFT
#define DCPU_RESET_MASK
#define DCPU_CLK_DISABLE_SHIFT

/* DCPU return codes */
#define DCPU_RET_ERROR_BIT
#define DCPU_RET_SUCCESS
#define DCPU_RET_ERR_HEADER
#define DCPU_RET_ERR_INVAL
#define DCPU_RET_ERR_CHKSUM
#define DCPU_RET_ERR_COMMAND
/* This error code is not firmware defined and only used in the driver. */
#define DCPU_RET_ERR_TIMEDOUT

/* Firmware magic */
#define DPFE_BE_MAGIC
#define DPFE_LE_MAGIC

/* Error codes */
#define ERR_INVALID_MAGIC
#define ERR_INVALID_SIZE
#define ERR_INVALID_CHKSUM

/* Message types */
#define DPFE_MSG_TYPE_COMMAND
#define DPFE_MSG_TYPE_RESPONSE

#define DELAY_LOOP_MAX

enum dpfe_msg_fields {};

enum dpfe_commands {};

/*
 * Format of the binary firmware file:
 *
 *   entry
 *      0    header
 *              value:  0xfe0101fe  <== little endian
 *                      0xfe1010fe  <== big endian
 *      1    sequence:
 *              [31:16] total segments on this build
 *              [15:0]  this segment sequence.
 *      2    FW version
 *      3    IMEM byte size
 *      4    DMEM byte size
 *           IMEM
 *           DMEM
 *      last checksum ==> sum of everything
 */
struct dpfe_firmware_header {};

/* Things we only need during initialization. */
struct init_data {};

/* API version and corresponding commands */
struct dpfe_api {};

/* Things we need for as long as we are active. */
struct brcmstb_dpfe_priv {};

/*
 * Forward declaration of our sysfs attribute functions, so we can declare the
 * attribute data structures early.
 */
static ssize_t show_info(struct device *, struct device_attribute *, char *);
static ssize_t show_refresh(struct device *, struct device_attribute *, char *);
static ssize_t store_refresh(struct device *, struct device_attribute *,
			  const char *, size_t);
static ssize_t show_vendor(struct device *, struct device_attribute *, char *);
static ssize_t show_dram(struct device *, struct device_attribute *, char *);

/*
 * Declare our attributes early, so they can be referenced in the API data
 * structure. We need to do this, because the attributes depend on the API
 * version.
 */
static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL);
static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh);
static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL);
static DEVICE_ATTR(dpfe_dram, 0444, show_dram, NULL);

/* API v2 sysfs attributes */
static struct attribute *dpfe_v2_attrs[] =;
ATTRIBUTE_GROUPS();

/* API v3 sysfs attributes */
static struct attribute *dpfe_v3_attrs[] =;
ATTRIBUTE_GROUPS();

/*
 * Old API v2 firmware commands, as defined in the rev 0.61 specification, we
 * use a version set to 1 to denote that it is not compatible with the new API
 * v2 and onwards.
 */
static const struct dpfe_api dpfe_api_old_v2 =;

/*
 * API v2 firmware commands, as defined in the rev 0.8 specification, named new
 * v2 here
 */
static const struct dpfe_api dpfe_api_new_v2 =;

/* API v3 firmware commands */
static const struct dpfe_api dpfe_api_v3 =;

static const char *get_error_text(unsigned int i)
{}

static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
{}

static void __disable_dcpu(struct brcmstb_dpfe_priv *priv)
{}

static void __enable_dcpu(struct brcmstb_dpfe_priv *priv)
{}

static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
{}

static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
				 char *buf, ssize_t *size)
{}

static void __finalize_command(struct brcmstb_dpfe_priv *priv)
{}

static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd,
			  u32 result[])
{}

/* Ensure that the firmware file loaded meets all the requirements. */
static int __verify_firmware(struct init_data *init,
			     const struct firmware *fw)
{}

/* Verify checksum by reading back the firmware from co-processor RAM. */
static int __verify_fw_checksum(struct init_data *init,
				struct brcmstb_dpfe_priv *priv,
				const struct dpfe_firmware_header *header,
				u32 checksum)
{}

static int __write_firmware(u32 __iomem *mem, const u32 *fw,
			    unsigned int size, bool is_big_endian)
{}

static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
{}

static ssize_t generic_show(unsigned int command, u32 response[],
			    struct brcmstb_dpfe_priv *priv, char *buf)
{}

static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
			 char *buf)
{}

static ssize_t show_refresh(struct device *dev,
			    struct device_attribute *devattr, char *buf)
{}

static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
			  const char *buf, size_t count)
{}

static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
			   char *buf)
{}

static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
			 char *buf)
{}

static int brcmstb_dpfe_resume(struct platform_device *pdev)
{}

static int brcmstb_dpfe_probe(struct platform_device *pdev)
{}

static void brcmstb_dpfe_remove(struct platform_device *pdev)
{}

static const struct of_device_id brcmstb_dpfe_of_match[] =;
MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match);

static struct platform_driver brcmstb_dpfe_driver =;

module_platform_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();