brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 3da6112 Raw
203 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *4 * Copyright (c) 2011, The Linux Foundation. All rights reserved.5 */6#include <linux/of.h>7#include <linux/of_dma.h>8#include <linux/bitops.h>9#include <linux/mmc/host.h>10#include <linux/mmc/card.h>11#include "mmci.h"12 13/* Registers */14#define DML_CONFIG			0x0015#define PRODUCER_CRCI_MSK		GENMASK(1, 0)16#define PRODUCER_CRCI_DISABLE		017#define PRODUCER_CRCI_X_SEL		BIT(0)18#define PRODUCER_CRCI_Y_SEL		BIT(1)19#define CONSUMER_CRCI_MSK		GENMASK(3, 2)20#define CONSUMER_CRCI_DISABLE		021#define CONSUMER_CRCI_X_SEL		BIT(2)22#define CONSUMER_CRCI_Y_SEL		BIT(3)23#define PRODUCER_TRANS_END_EN		BIT(4)24#define BYPASS				BIT(16)25#define DIRECT_MODE			BIT(17)26#define INFINITE_CONS_TRANS		BIT(18)27 28#define DML_SW_RESET			0x0829#define DML_PRODUCER_START		0x0c30#define DML_CONSUMER_START		0x1031#define DML_PRODUCER_PIPE_LOGICAL_SIZE	0x1432#define DML_CONSUMER_PIPE_LOGICAL_SIZE	0x1833#define DML_PIPE_ID			0x1c34#define PRODUCER_PIPE_ID_SHFT		035#define PRODUCER_PIPE_ID_MSK		GENMASK(4, 0)36#define CONSUMER_PIPE_ID_SHFT		1637#define CONSUMER_PIPE_ID_MSK		GENMASK(20, 16)38 39#define DML_PRODUCER_BAM_BLOCK_SIZE	0x2440#define DML_PRODUCER_BAM_TRANS_SIZE	0x2841 42/* other definitions */43#define PRODUCER_PIPE_LOGICAL_SIZE	409644#define CONSUMER_PIPE_LOGICAL_SIZE	409645 46#define DML_OFFSET			0x80047 48static int qcom_dma_start(struct mmci_host *host, unsigned int *datactrl)49{50	u32 config;51	void __iomem *base = host->base + DML_OFFSET;52	struct mmc_data *data = host->data;53	int ret = mmci_dmae_start(host, datactrl);54 55	if (ret)56		return ret;57 58	if (data->flags & MMC_DATA_READ) {59		/* Read operation: configure DML for producer operation */60		/* Set producer CRCI-x and disable consumer CRCI */61		config = readl_relaxed(base + DML_CONFIG);62		config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;63		config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;64		writel_relaxed(config, base + DML_CONFIG);65 66		/* Set the Producer BAM block size */67		writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);68 69		/* Set Producer BAM Transaction size */70		writel_relaxed(data->blocks * data->blksz,71			       base + DML_PRODUCER_BAM_TRANS_SIZE);72		/* Set Producer Transaction End bit */73		config = readl_relaxed(base + DML_CONFIG);74		config |= PRODUCER_TRANS_END_EN;75		writel_relaxed(config, base + DML_CONFIG);76		/* Trigger producer */77		writel_relaxed(1, base + DML_PRODUCER_START);78	} else {79		/* Write operation: configure DML for consumer operation */80		/* Set consumer CRCI-x and disable producer CRCI*/81		config = readl_relaxed(base + DML_CONFIG);82		config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;83		config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;84		writel_relaxed(config, base + DML_CONFIG);85		/* Clear Producer Transaction End bit */86		config = readl_relaxed(base + DML_CONFIG);87		config &= ~PRODUCER_TRANS_END_EN;88		writel_relaxed(config, base + DML_CONFIG);89		/* Trigger consumer */90		writel_relaxed(1, base + DML_CONSUMER_START);91	}92 93	/* make sure the dml is configured before dma is triggered */94	wmb();95	return 0;96}97 98static int of_get_dml_pipe_index(struct device_node *np, const char *name)99{100	int index;101	struct of_phandle_args	dma_spec;102 103	index = of_property_match_string(np, "dma-names", name);104 105	if (index < 0)106		return -ENODEV;107 108	if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,109				       &dma_spec))110		return -ENODEV;111 112	if (dma_spec.args_count)113		return dma_spec.args[0];114 115	return -ENODEV;116}117 118/* Initialize the dml hardware connected to SD Card controller */119static int qcom_dma_setup(struct mmci_host *host)120{121	u32 config;122	void __iomem *base;123	int consumer_id, producer_id;124	struct device_node *np = host->mmc->parent->of_node;125 126	if (mmci_dmae_setup(host))127		return -EINVAL;128 129	consumer_id = of_get_dml_pipe_index(np, "tx");130	producer_id = of_get_dml_pipe_index(np, "rx");131 132	if (producer_id < 0 || consumer_id < 0) {133		mmci_dmae_release(host);134		return -EINVAL;135	}136 137	base = host->base + DML_OFFSET;138 139	/* Reset the DML block */140	writel_relaxed(1, base + DML_SW_RESET);141 142	/* Disable the producer and consumer CRCI */143	config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);144	/*145	 * Disable the bypass mode. Bypass mode will only be used146	 * if data transfer is to happen in PIO mode and don't147	 * want the BAM interface to connect with SDCC-DML.148	 */149	config &= ~BYPASS;150	/*151	 * Disable direct mode as we don't DML to MASTER the AHB bus.152	 * BAM connected with DML should MASTER the AHB bus.153	 */154	config &= ~DIRECT_MODE;155	/*156	 * Disable infinite mode transfer as we won't be doing any157	 * infinite size data transfers. All data transfer will be158	 * of finite data size.159	 */160	config &= ~INFINITE_CONS_TRANS;161	writel_relaxed(config, base + DML_CONFIG);162 163	/*164	 * Initialize the logical BAM pipe size for producer165	 * and consumer.166	 */167	writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,168		       base + DML_PRODUCER_PIPE_LOGICAL_SIZE);169	writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,170		       base + DML_CONSUMER_PIPE_LOGICAL_SIZE);171 172	/* Initialize Producer/consumer pipe id */173	writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),174		       base + DML_PIPE_ID);175 176	/* Make sure dml initialization is finished */177	mb();178 179	return 0;180}181 182static u32 qcom_get_dctrl_cfg(struct mmci_host *host)183{184	return MCI_DPSM_ENABLE | (host->data->blksz << 4);185}186 187static struct mmci_host_ops qcom_variant_ops = {188	.prep_data = mmci_dmae_prep_data,189	.unprep_data = mmci_dmae_unprep_data,190	.get_datactrl_cfg = qcom_get_dctrl_cfg,191	.get_next_data = mmci_dmae_get_next_data,192	.dma_setup = qcom_dma_setup,193	.dma_release = mmci_dmae_release,194	.dma_start = qcom_dma_start,195	.dma_finalize = mmci_dmae_finalize,196	.dma_error = mmci_dmae_error,197};198 199void qcom_variant_init(struct mmci_host *host)200{201	host->ops = &qcom_variant_ops;202}203