drivers/devfreq/event/rockchip-dfi.c

Source file repositories/reference/linux-study-clean/drivers/devfreq/event/rockchip-dfi.c

File Facts

System
Linux kernel
Corpus path
drivers/devfreq/event/rockchip-dfi.c
Extension
.c
Size
24285 bytes
Lines
890
Domain
Driver Families
Bucket
drivers/devfreq
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct dmc_count_channel {
	u64 access;
	u64 clock_cycles;
	u64 read_access;
	u64 write_access;
};

struct dmc_count {
	struct dmc_count_channel c[DMC_MAX_CHANNELS];
};

/*
 * The dfi controller can monitor DDR load. It has an upper and lower threshold
 * for the operating points. Whenever the usage leaves these bounds an event is
 * generated to indicate the DDR frequency should be changed.
 */
struct rockchip_dfi {
	struct devfreq_event_dev *edev;
	struct devfreq_event_desc desc;
	struct dmc_count last_event_count;

	struct dmc_count last_perf_count;
	struct dmc_count total_count;
	seqlock_t count_seqlock; /* protects last_perf_count and total_count */

	struct device *dev;
	void __iomem *regs;
	struct regmap *regmap_pmu;
	struct clk *clk;
	int usecount;
	struct mutex mutex;
	u32 ddr_type;
	unsigned int channel_mask;
	unsigned int max_channels;
	enum cpuhp_state cpuhp_state;
	struct hlist_node node;
	struct pmu pmu;
	struct hrtimer timer;
	unsigned int cpu;
	int active_events;
	int burst_len;
	int buswidth[DMC_MAX_CHANNELS];
	int ddrmon_stride;
	bool ddrmon_ctrl_single;
	u32 lp5_bank_mode;
	bool lp5_ckr;	/* true if in 4:1 command-to-data clock ratio mode */
	unsigned int count_multiplier;	/* number of data clocks per count */
};

static int rockchip_dfi_ddrtype_to_ctrl(struct rockchip_dfi *dfi, u32 *ctrl)
{
	u32 ddrmon_ver;

	switch (dfi->ddr_type) {
	case ROCKCHIP_DDRTYPE_LPDDR2:
	case ROCKCHIP_DDRTYPE_LPDDR3:
		*ctrl = FIELD_PREP_WM16(DDRMON_CTRL_LPDDR23, 1) |
			FIELD_PREP_WM16(DDRMON_CTRL_LPDDR4, 0) |
			FIELD_PREP_WM16(DDRMON_CTRL_LPDDR5, 0);
		break;
	case ROCKCHIP_DDRTYPE_LPDDR4:
	case ROCKCHIP_DDRTYPE_LPDDR4X:
		*ctrl = FIELD_PREP_WM16(DDRMON_CTRL_LPDDR23, 0) |
			FIELD_PREP_WM16(DDRMON_CTRL_LPDDR4, 1) |
			FIELD_PREP_WM16(DDRMON_CTRL_LPDDR5, 0);
		break;
	case ROCKCHIP_DDRTYPE_LPDDR5:
		ddrmon_ver = readl_relaxed(dfi->regs);
		if (ddrmon_ver < 0x40) {
			*ctrl = FIELD_PREP_WM16(DDRMON_CTRL_LPDDR23, 0) |
				FIELD_PREP_WM16(DDRMON_CTRL_LPDDR4, 0) |
				FIELD_PREP_WM16(DDRMON_CTRL_LPDDR5, 1) |
				FIELD_PREP_WM16(DDRMON_CTRL_LP5_BANK_MODE_MASK,
						dfi->lp5_bank_mode);
			break;
		}

		/*
		 * As it is unknown whether the unpleasant special case
		 * behaviour used by the vendor kernel is needed for any
		 * shipping hardware, ask users to report if they have
		 * some of that hardware.
		 */
		dev_err(&dfi->edev->dev,
			"unsupported DDRMON version 0x%04X, please let linux-rockchip know!\n",
			ddrmon_ver);
		return -EOPNOTSUPP;
	default:
		dev_err(&dfi->edev->dev, "unsupported memory type 0x%X\n",
			dfi->ddr_type);

Annotation

Implementation Notes