Exemple #1
0
int ocmem_rdm_init(struct platform_device *pdev)
{

	struct ocmem_plat_data *pdata = NULL;
	int rc = 0;

	pdata = platform_get_drvdata(pdev);

	br_base = pdata->br_base;
	dm_base = pdata->dm_base;

	rc = devm_request_irq(&pdev->dev, pdata->dm_irq, ocmem_dm_irq_handler,
				IRQF_TRIGGER_RISING, "ocmem_dm_irq", pdata);

	if (rc) {
		dev_err(&pdev->dev, "Failed to request dm irq");
		return -EINVAL;
	}

	rc = ocmem_enable_core_clock();

	if (rc < 0) {
		pr_err("RDM initialization failed\n");
		return rc;
	}

	init_completion(&dm_clear_event);
	init_completion(&dm_transfer_event);
	ocmem_disable_core_clock();
	return 0;
}
int ocmem_core_init(struct platform_device *pdev)
{
	struct device   *dev = &pdev->dev;
	struct ocmem_plat_data *pdata = NULL;
	unsigned hw_ver;
	bool interleaved;
	unsigned i, j, k;
	unsigned rsc_type = 0;
	int rc = 0;

	pdata = platform_get_drvdata(pdev);
	ocmem_base = pdata->reg_base;

	rc = ocmem_enable_core_clock();

	if (rc < 0)
		return rc;

	hw_ver = ocmem_read(ocmem_base + OC_HW_PROFILE);

	if (pdata->nr_regions != OCMEM_V1_REGIONS) {
		pr_err("Invalid number of regions (%d)\n", pdata->nr_regions);
		goto hw_not_supported;
	}

	num_macros = (hw_ver & NUM_MACROS_MASK) >> NUM_MACROS_SHIFT;
	num_ports = (hw_ver & NUM_PORTS_MASK) >> NUM_PORTS_SHIFT;

	if (num_macros != OCMEM_V1_MACROS) {
		pr_err("Invalid number of macros (%d)\n", pdata->nr_macros);
		goto hw_not_supported;
	}

	interleaved = (hw_ver & INTERLEAVING_MASK) >> INTERLEAVING_SHIFT;

	if (interleaved == false) {
		pr_err("Interleaving is disabled\n");
		goto hw_not_supported;
	}

	num_regions = pdata->nr_regions;

	pdata->interleaved = true;
	pdata->nr_macros = num_macros;
	pdata->nr_ports = num_ports;
	macro_size = OCMEM_V1_MACRO_SZ * 2;
	num_banks = num_ports / 2;
	region_size = macro_size * num_banks;
	rsc_type = pdata->rpm_rsc_type;

	pr_debug("ocmem_core: ports %d regions %d macros %d interleaved %d\n",
				num_ports, num_regions, num_macros,
				interleaved);

	region_ctrl = devm_kzalloc(dev, sizeof(struct ocmem_hw_region)
					 * num_regions, GFP_KERNEL);

	if (!region_ctrl) {
		goto err_no_mem;
	}

	mutex_init(&region_ctrl_lock);

	for (i = 0 ; i < num_regions; i++) {
		struct ocmem_hw_region *region = &region_ctrl[i];
		struct msm_rpm_request *req = NULL;
		region->interleaved = interleaved;
		region->mode = MODE_DEFAULT;
		region->r_state = REGION_DEFAULT_OFF;
		region->num_macros = num_banks;

		region->macro = devm_kzalloc(dev,
					sizeof(struct ocmem_hw_macro) *
						num_banks, GFP_KERNEL);
		if (!region->macro) {
			goto err_no_mem;
		}

		for (j = 0; j < num_banks; j++) {
			struct ocmem_hw_macro *m = &region->macro[j];
			m->m_state = MACRO_OFF;
			for (k = 0; k < OCMEM_CLIENT_MAX; k++) {
				atomic_set(&m->m_on[k], 0);
				atomic_set(&m->m_retain[k], 0);
			}
		}

		if (pdata->rpm_pwr_ctrl) {
			rpm_power_control = true;
			req = msm_rpm_create_request(MSM_RPM_CTX_ACTIVE_SET,
					rsc_type, i, num_banks);

			if (!req) {
				pr_err("Unable to create RPM request\n");
				goto region_init_error;
			}

			pr_debug("rpm request type %x (rsc: %d) with %d elements\n",
						rsc_type, i, num_banks);

			region->rpm_req = req;
		}

		if (ocmem_region_toggle(i)) {
			pr_err("Failed to verify region %d\n", i);
			goto region_init_error;
		}

		if (ocmem_region_set_default_state(i)) {
			pr_err("Failed to initialize region %d\n", i);
			goto region_init_error;
		}
	}

	rc = ocmem_core_set_default_state();

	if (rc < 0)
		return rc;

	ocmem_disable_core_clock();
	return 0;

err_no_mem:
	pr_err("ocmem: Unable to allocate memory\n");
region_init_error:
hw_not_supported:
	pr_err("Unsupported OCMEM h/w configuration %x\n", hw_ver);
	ocmem_disable_core_clock();
	return -EINVAL;
}
Exemple #3
0
/* Lock during transfers */
int ocmem_rdm_transfer(int id, struct ocmem_map_list *clist,
			unsigned long start, int direction)
{
	int num_chunks = clist->num_chunks;
	int slot = client_slot_start(id);
	int table_start = 0;
	int table_end = 0;
	int br_ctrl = 0;
	int br_id = 0;
	int client_id = 0;
	int dm_ctrl = 0;
	int i = 0;
	int j = 0;
	int status = 0;
	int rc = 0;

	rc = ocmem_enable_core_clock();

	if (rc < 0) {
		pr_err("RDM transfer failed for client %s (id: %d)\n",
				get_name(id), id);
		return rc;
	}

	/* Clear DM Mask */
	ocmem_write(DM_MASK_RESET, dm_base + DM_INTR_MASK);
	/* Clear DM Interrupts */
	ocmem_write(DM_INTR_RESET, dm_base + DM_INTR_CLR);

	for (i = 0, j = slot; i < num_chunks; i++, j++) {

		struct ocmem_chunk *chunk = &clist->chunks[i];
		int sz = chunk->size;
		int paddr = chunk->ddr_paddr;
		int tbl_n_ctrl = 0;

		tbl_n_ctrl |= BR_TBL_ENTRY_ENABLE;
		if (chunk->ro)
			tbl_n_ctrl |= (1 << BR_RW_SHIFT);

		/* Table Entry n of BR and DM */
		ocmem_write(start, br_base + BR_TBL_n_offset(j));
		ocmem_write(sz, br_base + BR_TBL_n_size(j));
		ocmem_write(paddr, br_base + BR_TBL_n_paddr(j));
		ocmem_write(tbl_n_ctrl, br_base + BR_TBL_n_ctrl(j));

		ocmem_write(start, dm_base + DM_TBL_n_offset(j));
		ocmem_write(sz, dm_base + DM_TBL_n_size(j));
		ocmem_write(paddr, dm_base + DM_TBL_n_paddr(j));
		ocmem_write(tbl_n_ctrl, dm_base + DM_TBL_n_ctrl(j));

		start += sz;
	}

	br_id = client_ctrl_id(id);
	table_start = slot;
	table_end = slot + num_chunks - 1;
	br_ctrl |= (table_start << BR_TBL_START);
	br_ctrl |= (table_end << BR_TBL_END);

	ocmem_write(br_ctrl, (br_base + BR_CLIENT_n_ctrl(br_id)));
	/* Enable BR */
	ocmem_write(0x1, br_base + BR_CTRL);

	/* Compute DM Control Value */
	dm_ctrl |= (table_start << DM_TBL_START);
	dm_ctrl |= (table_end << DM_TBL_END);

	client_id = client_ctrl_id(id);
	dm_ctrl |= (client_id << DM_CLIENT_SHIFT);
	dm_ctrl |= (DM_BR_ID_LPASS << DM_BR_ID_SHIFT);
	dm_ctrl |= (DM_BLOCK_256 << DM_BR_BLK_SHIFT);
	dm_ctrl |= (direction << DM_DIR_SHIFT);

	status = ocmem_read(dm_base + DM_GEN_STATUS);
	pr_debug("Transfer status before %x\n", status);
	INIT_COMPLETION(dm_transfer_event);
	/* The DM and BR tables must be programmed before triggering the
	 * Data Mover else the coherent transfer would be corrupted
	 */
	mb();
	/* Trigger DM */
	ocmem_write(dm_ctrl, dm_base + DM_CTRL);
	pr_debug("ocmem: rdm: dm_ctrl %x br_ctrl %x\n", dm_ctrl, br_ctrl);

	wait_for_completion(&dm_transfer_event);
	pr_debug("Completed transferring %d segments\n", num_chunks);
	ocmem_disable_core_clock();
	return 0;
}
static int switch_power_state(int id, unsigned long offset, unsigned long len,
			unsigned new_state)
{
	unsigned region_start = num_regions;
	unsigned region_end = num_regions;
	unsigned curr_state = 0x0;
	int i = 0;
	int j = 0;
	unsigned start_m = num_banks;
	unsigned end_m = num_banks;
	unsigned long region_offset = 0;
	int rc = 0;

	if (offset < 0)
		return -EINVAL;

	if (len < macro_size)
		return -EINVAL;


	pr_debug("ocmem: power_transition to %x for client %d\n", new_state,
							id);

	region_start = offset / region_size;
	region_end = (offset + len - 1) / region_size;

	pr_debug("ocmem: region start %u end %u\n", region_start, region_end);

	if (region_start >= num_regions ||
		(region_end >= num_regions))
			return -EINVAL;

	rc = ocmem_enable_core_clock();

	if (rc < 0) {
		pr_err("ocmem: Power transistion request for client %s (id: %d) failed\n",
				get_name(id), id);
		return rc;
	}

	mutex_lock(&region_ctrl_lock);

	for (i = region_start; i <= region_end; i++) {

		curr_state = read_region_state(i);

		switch (curr_state) {
		case REGION_DEFAULT_OFF:
			if (new_state != REGION_DEFAULT_ON)
				goto invalid_transition;
			break;
		case REGION_DEFAULT_RETENTION:
			if (new_state != REGION_DEFAULT_ON)
				goto invalid_transition;
			break;
		default:
			break;
		}

		if (len >= region_size) {
			pr_debug("switch: entire region (%d)\n", i);
			start_m = 0;
			end_m = num_banks;
		} else {
			region_offset = offset - (i * region_size);
			start_m = region_offset / macro_size;
			end_m = (region_offset + len - 1) / macro_size;
			pr_debug("switch: macro (%u to %u)\n", start_m, end_m);
		}

		for (j = start_m; j <= end_m; j++) {
			pr_debug("vote: macro (%d) region (%d)\n", j, i);
			apply_macro_vote(id, i, j,
				hw_macro_state(new_state));
			aggregate_macro_state(i, j);
		}
		aggregate_region_state(i);
		commit_region_state(i);
		len -= region_size;

		/* If we voted ON/retain the banks must never be OFF */
		if (new_state != REGION_DEFAULT_OFF) {
			if (memory_is_off(i)) {
				pr_err("ocmem: Accessing memory during sleep\n");
				WARN_ON(1);
			}
		}

	}
	mutex_unlock(&region_ctrl_lock);
	ocmem_disable_core_clock();
	return 0;
invalid_transition:
	mutex_unlock(&region_ctrl_lock);
	ocmem_disable_core_clock();
	pr_err("ocmem_core: Invalid state transition detected for %d\n", id);
	pr_err("ocmem_core: Offset %lx Len %lx curr_state %x new_state %x\n",
			offset, len, curr_state, new_state);
	WARN_ON(1);
	return -EINVAL;
}