18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-1.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Renesas USB driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2011 Renesas Solutions Corp.
68c2ecf20Sopenharmony_ci * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/slab.h>
108c2ecf20Sopenharmony_ci#include "common.h"
118c2ecf20Sopenharmony_ci#include "pipe.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci *		macros
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci#define usbhsp_addr_offset(p)	((usbhs_pipe_number(p) - 1) * 2)
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define usbhsp_flags_set(p, f)	((p)->flags |=  USBHS_PIPE_FLAGS_##f)
198c2ecf20Sopenharmony_ci#define usbhsp_flags_clr(p, f)	((p)->flags &= ~USBHS_PIPE_FLAGS_##f)
208c2ecf20Sopenharmony_ci#define usbhsp_flags_has(p, f)	((p)->flags &   USBHS_PIPE_FLAGS_##f)
218c2ecf20Sopenharmony_ci#define usbhsp_flags_init(p)	do {(p)->flags = 0; } while (0)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci/*
248c2ecf20Sopenharmony_ci * for debug
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_cistatic char *usbhsp_pipe_name[] = {
278c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_CONTROL]	= "DCP",
288c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_BULK]	= "BULK",
298c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_INT]		= "INT",
308c2ecf20Sopenharmony_ci	[USB_ENDPOINT_XFER_ISOC]	= "ISO",
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cichar *usbhs_pipe_name(struct usbhs_pipe *pipe)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	return usbhsp_pipe_name[usbhs_pipe_type(pipe)];
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic struct renesas_usbhs_driver_pipe_config
398c2ecf20Sopenharmony_ci*usbhsp_get_pipe_config(struct usbhs_priv *priv, int pipe_num)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	struct renesas_usbhs_driver_pipe_config *pipe_configs =
428c2ecf20Sopenharmony_ci					usbhs_get_dparam(priv, pipe_configs);
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	return &pipe_configs[pipe_num];
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci *		DCPCTR/PIPEnCTR functions
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
538c2ecf20Sopenharmony_ci	int offset = usbhsp_addr_offset(pipe);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
568c2ecf20Sopenharmony_ci		usbhs_bset(priv, DCPCTR, mask, val);
578c2ecf20Sopenharmony_ci	else
588c2ecf20Sopenharmony_ci		usbhs_bset(priv, PIPEnCTR + offset, mask, val);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistatic u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe)
628c2ecf20Sopenharmony_ci{
638c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
648c2ecf20Sopenharmony_ci	int offset = usbhsp_addr_offset(pipe);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
678c2ecf20Sopenharmony_ci		return usbhs_read(priv, DCPCTR);
688c2ecf20Sopenharmony_ci	else
698c2ecf20Sopenharmony_ci		return usbhs_read(priv, PIPEnCTR + offset);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci *		DCP/PIPE functions
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe,
768c2ecf20Sopenharmony_ci				  u16 dcp_reg, u16 pipe_reg,
778c2ecf20Sopenharmony_ci				  u16 mask, u16 val)
788c2ecf20Sopenharmony_ci{
798c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
828c2ecf20Sopenharmony_ci		usbhs_bset(priv, dcp_reg, mask, val);
838c2ecf20Sopenharmony_ci	else
848c2ecf20Sopenharmony_ci		usbhs_bset(priv, pipe_reg, mask, val);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe,
888c2ecf20Sopenharmony_ci				 u16 dcp_reg, u16 pipe_reg)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
938c2ecf20Sopenharmony_ci		return usbhs_read(priv, dcp_reg);
948c2ecf20Sopenharmony_ci	else
958c2ecf20Sopenharmony_ci		return usbhs_read(priv, pipe_reg);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/*
998c2ecf20Sopenharmony_ci *		DCPCFG/PIPECFG functions
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	__usbhsp_pipe_xxx_set(pipe, DCPCFG, PIPECFG, mask, val);
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic u16 usbhsp_pipe_cfg_get(struct usbhs_pipe *pipe)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	return __usbhsp_pipe_xxx_get(pipe, DCPCFG, PIPECFG);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/*
1128c2ecf20Sopenharmony_ci *		PIPEnTRN/PIPEnTRE functions
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_cistatic void usbhsp_pipe_trn_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
1178c2ecf20Sopenharmony_ci	struct device *dev = usbhs_priv_to_dev(priv);
1188c2ecf20Sopenharmony_ci	int num = usbhs_pipe_number(pipe);
1198c2ecf20Sopenharmony_ci	u16 reg;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	/*
1228c2ecf20Sopenharmony_ci	 * It is impossible to calculate address,
1238c2ecf20Sopenharmony_ci	 * since PIPEnTRN addresses were mapped randomly.
1248c2ecf20Sopenharmony_ci	 */
1258c2ecf20Sopenharmony_ci#define CASE_PIPExTRN(a)		\
1268c2ecf20Sopenharmony_ci	case 0x ## a:			\
1278c2ecf20Sopenharmony_ci		reg = PIPE ## a ## TRN;	\
1288c2ecf20Sopenharmony_ci		break;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	switch (num) {
1318c2ecf20Sopenharmony_ci	CASE_PIPExTRN(1);
1328c2ecf20Sopenharmony_ci	CASE_PIPExTRN(2);
1338c2ecf20Sopenharmony_ci	CASE_PIPExTRN(3);
1348c2ecf20Sopenharmony_ci	CASE_PIPExTRN(4);
1358c2ecf20Sopenharmony_ci	CASE_PIPExTRN(5);
1368c2ecf20Sopenharmony_ci	CASE_PIPExTRN(B);
1378c2ecf20Sopenharmony_ci	CASE_PIPExTRN(C);
1388c2ecf20Sopenharmony_ci	CASE_PIPExTRN(D);
1398c2ecf20Sopenharmony_ci	CASE_PIPExTRN(E);
1408c2ecf20Sopenharmony_ci	CASE_PIPExTRN(F);
1418c2ecf20Sopenharmony_ci	CASE_PIPExTRN(9);
1428c2ecf20Sopenharmony_ci	CASE_PIPExTRN(A);
1438c2ecf20Sopenharmony_ci	default:
1448c2ecf20Sopenharmony_ci		dev_err(dev, "unknown pipe (%d)\n", num);
1458c2ecf20Sopenharmony_ci		return;
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci	__usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic void usbhsp_pipe_tre_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
1518c2ecf20Sopenharmony_ci{
1528c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
1538c2ecf20Sopenharmony_ci	struct device *dev = usbhs_priv_to_dev(priv);
1548c2ecf20Sopenharmony_ci	int num = usbhs_pipe_number(pipe);
1558c2ecf20Sopenharmony_ci	u16 reg;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/*
1588c2ecf20Sopenharmony_ci	 * It is impossible to calculate address,
1598c2ecf20Sopenharmony_ci	 * since PIPEnTRE addresses were mapped randomly.
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci#define CASE_PIPExTRE(a)			\
1628c2ecf20Sopenharmony_ci	case 0x ## a:				\
1638c2ecf20Sopenharmony_ci		reg = PIPE ## a ## TRE;		\
1648c2ecf20Sopenharmony_ci		break;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	switch (num) {
1678c2ecf20Sopenharmony_ci	CASE_PIPExTRE(1);
1688c2ecf20Sopenharmony_ci	CASE_PIPExTRE(2);
1698c2ecf20Sopenharmony_ci	CASE_PIPExTRE(3);
1708c2ecf20Sopenharmony_ci	CASE_PIPExTRE(4);
1718c2ecf20Sopenharmony_ci	CASE_PIPExTRE(5);
1728c2ecf20Sopenharmony_ci	CASE_PIPExTRE(B);
1738c2ecf20Sopenharmony_ci	CASE_PIPExTRE(C);
1748c2ecf20Sopenharmony_ci	CASE_PIPExTRE(D);
1758c2ecf20Sopenharmony_ci	CASE_PIPExTRE(E);
1768c2ecf20Sopenharmony_ci	CASE_PIPExTRE(F);
1778c2ecf20Sopenharmony_ci	CASE_PIPExTRE(9);
1788c2ecf20Sopenharmony_ci	CASE_PIPExTRE(A);
1798c2ecf20Sopenharmony_ci	default:
1808c2ecf20Sopenharmony_ci		dev_err(dev, "unknown pipe (%d)\n", num);
1818c2ecf20Sopenharmony_ci		return;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	__usbhsp_pipe_xxx_set(pipe, 0, reg, mask, val);
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci/*
1888c2ecf20Sopenharmony_ci *		PIPEBUF
1898c2ecf20Sopenharmony_ci */
1908c2ecf20Sopenharmony_cistatic void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
1938c2ecf20Sopenharmony_ci		return;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	__usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci/*
1998c2ecf20Sopenharmony_ci *		DCPMAXP/PIPEMAXP
2008c2ecf20Sopenharmony_ci */
2018c2ecf20Sopenharmony_cistatic void usbhsp_pipe_maxp_set(struct usbhs_pipe *pipe, u16 mask, u16 val)
2028c2ecf20Sopenharmony_ci{
2038c2ecf20Sopenharmony_ci	__usbhsp_pipe_xxx_set(pipe, DCPMAXP, PIPEMAXP, mask, val);
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci/*
2078c2ecf20Sopenharmony_ci *		pipe control functions
2088c2ecf20Sopenharmony_ci */
2098c2ecf20Sopenharmony_cistatic void usbhsp_pipe_select(struct usbhs_pipe *pipe)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	/*
2148c2ecf20Sopenharmony_ci	 * On pipe, this is necessary before
2158c2ecf20Sopenharmony_ci	 * accesses to below registers.
2168c2ecf20Sopenharmony_ci	 *
2178c2ecf20Sopenharmony_ci	 * PIPESEL	: usbhsp_pipe_select
2188c2ecf20Sopenharmony_ci	 * PIPECFG	: usbhsp_pipe_cfg_xxx
2198c2ecf20Sopenharmony_ci	 * PIPEBUF	: usbhsp_pipe_buf_xxx
2208c2ecf20Sopenharmony_ci	 * PIPEMAXP	: usbhsp_pipe_maxp_xxx
2218c2ecf20Sopenharmony_ci	 * PIPEPERI
2228c2ecf20Sopenharmony_ci	 */
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	/*
2258c2ecf20Sopenharmony_ci	 * if pipe is dcp, no pipe is selected.
2268c2ecf20Sopenharmony_ci	 * it is no problem, because dcp have its register
2278c2ecf20Sopenharmony_ci	 */
2288c2ecf20Sopenharmony_ci	usbhs_write(priv, PIPESEL, 0xF & usbhs_pipe_number(pipe));
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int usbhsp_pipe_barrier(struct usbhs_pipe *pipe)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
2348c2ecf20Sopenharmony_ci	int timeout = 1024;
2358c2ecf20Sopenharmony_ci	u16 mask = usbhs_mod_is_host(priv) ? (CSSTS | PID_MASK) : PID_MASK;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	/*
2388c2ecf20Sopenharmony_ci	 * make sure....
2398c2ecf20Sopenharmony_ci	 *
2408c2ecf20Sopenharmony_ci	 * Modify these bits when CSSTS = 0, PID = NAK, and no pipe number is
2418c2ecf20Sopenharmony_ci	 * specified by the CURPIPE bits.
2428c2ecf20Sopenharmony_ci	 * When changing the setting of this bit after changing
2438c2ecf20Sopenharmony_ci	 * the PID bits for the selected pipe from BUF to NAK,
2448c2ecf20Sopenharmony_ci	 * check that CSSTS = 0 and PBUSY = 0.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/*
2488c2ecf20Sopenharmony_ci	 * CURPIPE bit = 0
2498c2ecf20Sopenharmony_ci	 *
2508c2ecf20Sopenharmony_ci	 * see also
2518c2ecf20Sopenharmony_ci	 *  "Operation"
2528c2ecf20Sopenharmony_ci	 *  - "Pipe Control"
2538c2ecf20Sopenharmony_ci	 *   - "Pipe Control Registers Switching Procedure"
2548c2ecf20Sopenharmony_ci	 */
2558c2ecf20Sopenharmony_ci	usbhs_write(priv, CFIFOSEL, 0);
2568c2ecf20Sopenharmony_ci	usbhs_pipe_disable(pipe);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	do {
2598c2ecf20Sopenharmony_ci		if (!(usbhsp_pipectrl_get(pipe) & mask))
2608c2ecf20Sopenharmony_ci			return 0;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		udelay(10);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	} while (timeout--);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return -EBUSY;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ciint usbhs_pipe_is_accessible(struct usbhs_pipe *pipe)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	u16 val;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	val = usbhsp_pipectrl_get(pipe);
2748c2ecf20Sopenharmony_ci	if (val & BSTS)
2758c2ecf20Sopenharmony_ci		return 0;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return -EBUSY;
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cibool usbhs_pipe_contains_transmittable_data(struct usbhs_pipe *pipe)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	u16 val;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* Do not support for DCP pipe */
2858c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
2868c2ecf20Sopenharmony_ci		return false;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	val = usbhsp_pipectrl_get(pipe);
2898c2ecf20Sopenharmony_ci	if (val & INBUFM)
2908c2ecf20Sopenharmony_ci		return true;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	return false;
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci/*
2968c2ecf20Sopenharmony_ci *		PID ctrl
2978c2ecf20Sopenharmony_ci */
2988c2ecf20Sopenharmony_cistatic void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	u16 pid = usbhsp_pipectrl_get(pipe);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	pid &= PID_MASK;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/*
3058c2ecf20Sopenharmony_ci	 * see
3068c2ecf20Sopenharmony_ci	 * "Pipe n Control Register" - "PID"
3078c2ecf20Sopenharmony_ci	 */
3088c2ecf20Sopenharmony_ci	switch (pid) {
3098c2ecf20Sopenharmony_ci	case PID_STALL11:
3108c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10);
3118c2ecf20Sopenharmony_ci		fallthrough;
3128c2ecf20Sopenharmony_ci	case PID_STALL10:
3138c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK);
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_civoid usbhs_pipe_disable(struct usbhs_pipe *pipe)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	int timeout = 1024;
3208c2ecf20Sopenharmony_ci	u16 val;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* see "Pipe n Control Register" - "PID" */
3238c2ecf20Sopenharmony_ci	__usbhsp_pid_try_nak_if_stall(pipe);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	usbhsp_pipectrl_set(pipe, PID_MASK, PID_NAK);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	do {
3288c2ecf20Sopenharmony_ci		val  = usbhsp_pipectrl_get(pipe);
3298c2ecf20Sopenharmony_ci		val &= PBUSY;
3308c2ecf20Sopenharmony_ci		if (!val)
3318c2ecf20Sopenharmony_ci			break;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci		udelay(10);
3348c2ecf20Sopenharmony_ci	} while (timeout--);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_civoid usbhs_pipe_enable(struct usbhs_pipe *pipe)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	/* see "Pipe n Control Register" - "PID" */
3408c2ecf20Sopenharmony_ci	__usbhsp_pid_try_nak_if_stall(pipe);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_civoid usbhs_pipe_stall(struct usbhs_pipe *pipe)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	u16 pid = usbhsp_pipectrl_get(pipe);
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	pid &= PID_MASK;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/*
3528c2ecf20Sopenharmony_ci	 * see
3538c2ecf20Sopenharmony_ci	 * "Pipe n Control Register" - "PID"
3548c2ecf20Sopenharmony_ci	 */
3558c2ecf20Sopenharmony_ci	switch (pid) {
3568c2ecf20Sopenharmony_ci	case PID_NAK:
3578c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL10);
3588c2ecf20Sopenharmony_ci		break;
3598c2ecf20Sopenharmony_ci	case PID_BUF:
3608c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, PID_MASK, PID_STALL11);
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ciint usbhs_pipe_is_stall(struct usbhs_pipe *pipe)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return (int)(pid == PID_STALL10 || pid == PID_STALL11);
3708c2ecf20Sopenharmony_ci}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_civoid usbhs_pipe_set_trans_count_if_bulk(struct usbhs_pipe *pipe, int len)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	if (!usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
3758c2ecf20Sopenharmony_ci		return;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/*
3788c2ecf20Sopenharmony_ci	 * clear and disable transfer counter for IN/OUT pipe
3798c2ecf20Sopenharmony_ci	 */
3808c2ecf20Sopenharmony_ci	usbhsp_pipe_tre_set(pipe, TRCLR | TRENB, TRCLR);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/*
3838c2ecf20Sopenharmony_ci	 * Only IN direction bulk pipe can use transfer count.
3848c2ecf20Sopenharmony_ci	 * Without using this function,
3858c2ecf20Sopenharmony_ci	 * received data will break if it was large data size.
3868c2ecf20Sopenharmony_ci	 * see PIPEnTRN/PIPEnTRE for detail
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dir_in(pipe)) {
3898c2ecf20Sopenharmony_ci		int maxp = usbhs_pipe_get_maxpacket(pipe);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci		usbhsp_pipe_trn_set(pipe, 0xffff, DIV_ROUND_UP(len, maxp));
3928c2ecf20Sopenharmony_ci		usbhsp_pipe_tre_set(pipe, TRENB, TRENB); /* enable */
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci/*
3988c2ecf20Sopenharmony_ci *		pipe setup
3998c2ecf20Sopenharmony_ci */
4008c2ecf20Sopenharmony_cistatic int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host,
4018c2ecf20Sopenharmony_ci				int dir_in, u16 *pipecfg)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	u16 type = 0;
4048c2ecf20Sopenharmony_ci	u16 bfre = 0;
4058c2ecf20Sopenharmony_ci	u16 dblb = 0;
4068c2ecf20Sopenharmony_ci	u16 cntmd = 0;
4078c2ecf20Sopenharmony_ci	u16 dir = 0;
4088c2ecf20Sopenharmony_ci	u16 epnum = 0;
4098c2ecf20Sopenharmony_ci	u16 shtnak = 0;
4108c2ecf20Sopenharmony_ci	static const u16 type_array[] = {
4118c2ecf20Sopenharmony_ci		[USB_ENDPOINT_XFER_BULK] = TYPE_BULK,
4128c2ecf20Sopenharmony_ci		[USB_ENDPOINT_XFER_INT]  = TYPE_INT,
4138c2ecf20Sopenharmony_ci		[USB_ENDPOINT_XFER_ISOC] = TYPE_ISO,
4148c2ecf20Sopenharmony_ci	};
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
4178c2ecf20Sopenharmony_ci		return -EINVAL;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/*
4208c2ecf20Sopenharmony_ci	 * PIPECFG
4218c2ecf20Sopenharmony_ci	 *
4228c2ecf20Sopenharmony_ci	 * see
4238c2ecf20Sopenharmony_ci	 *  - "Register Descriptions" - "PIPECFG" register
4248c2ecf20Sopenharmony_ci	 *  - "Features"  - "Pipe configuration"
4258c2ecf20Sopenharmony_ci	 *  - "Operation" - "Pipe Control"
4268c2ecf20Sopenharmony_ci	 */
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	/* TYPE */
4298c2ecf20Sopenharmony_ci	type = type_array[usbhs_pipe_type(pipe)];
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* BFRE */
4328c2ecf20Sopenharmony_ci	if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_ISOC) ||
4338c2ecf20Sopenharmony_ci	    usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
4348c2ecf20Sopenharmony_ci		bfre = 0; /* FIXME */
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* DBLB: see usbhs_pipe_config_update() */
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* CNTMD */
4398c2ecf20Sopenharmony_ci	if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK))
4408c2ecf20Sopenharmony_ci		cntmd = 0; /* FIXME */
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/* DIR */
4438c2ecf20Sopenharmony_ci	if (dir_in)
4448c2ecf20Sopenharmony_ci		usbhsp_flags_set(pipe, IS_DIR_HOST);
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	if (!!is_host ^ !!dir_in)
4478c2ecf20Sopenharmony_ci		dir |= DIR_OUT;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	if (!dir)
4508c2ecf20Sopenharmony_ci		usbhsp_flags_set(pipe, IS_DIR_IN);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* SHTNAK */
4538c2ecf20Sopenharmony_ci	if (usbhs_pipe_type_is(pipe, USB_ENDPOINT_XFER_BULK) &&
4548c2ecf20Sopenharmony_ci	    !dir)
4558c2ecf20Sopenharmony_ci		shtnak = SHTNAK;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* EPNUM */
4588c2ecf20Sopenharmony_ci	epnum = 0; /* see usbhs_pipe_config_update() */
4598c2ecf20Sopenharmony_ci	*pipecfg = type		|
4608c2ecf20Sopenharmony_ci		   bfre		|
4618c2ecf20Sopenharmony_ci		   dblb		|
4628c2ecf20Sopenharmony_ci		   cntmd	|
4638c2ecf20Sopenharmony_ci		   dir		|
4648c2ecf20Sopenharmony_ci		   shtnak	|
4658c2ecf20Sopenharmony_ci		   epnum;
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
4728c2ecf20Sopenharmony_ci	struct device *dev = usbhs_priv_to_dev(priv);
4738c2ecf20Sopenharmony_ci	int pipe_num = usbhs_pipe_number(pipe);
4748c2ecf20Sopenharmony_ci	u16 buff_size;
4758c2ecf20Sopenharmony_ci	u16 bufnmb;
4768c2ecf20Sopenharmony_ci	u16 bufnmb_cnt;
4778c2ecf20Sopenharmony_ci	struct renesas_usbhs_driver_pipe_config *pipe_config =
4788c2ecf20Sopenharmony_ci					usbhsp_get_pipe_config(priv, pipe_num);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	/*
4818c2ecf20Sopenharmony_ci	 * PIPEBUF
4828c2ecf20Sopenharmony_ci	 *
4838c2ecf20Sopenharmony_ci	 * see
4848c2ecf20Sopenharmony_ci	 *  - "Register Descriptions" - "PIPEBUF" register
4858c2ecf20Sopenharmony_ci	 *  - "Features"  - "Pipe configuration"
4868c2ecf20Sopenharmony_ci	 *  - "Operation" - "FIFO Buffer Memory"
4878c2ecf20Sopenharmony_ci	 *  - "Operation" - "Pipe Control"
4888c2ecf20Sopenharmony_ci	 */
4898c2ecf20Sopenharmony_ci	buff_size = pipe_config->bufsize;
4908c2ecf20Sopenharmony_ci	bufnmb = pipe_config->bufnum;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	/* change buff_size to register value */
4938c2ecf20Sopenharmony_ci	bufnmb_cnt = (buff_size / 64) - 1;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	dev_dbg(dev, "pipe : %d : buff_size 0x%x: bufnmb 0x%x\n",
4968c2ecf20Sopenharmony_ci		pipe_num, buff_size, bufnmb);
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return	(0x1f & bufnmb_cnt)	<< 10 |
4998c2ecf20Sopenharmony_ci		(0xff & bufnmb)		<<  0;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_civoid usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
5038c2ecf20Sopenharmony_ci			      u16 epnum, u16 maxp)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
5068c2ecf20Sopenharmony_ci	int pipe_num = usbhs_pipe_number(pipe);
5078c2ecf20Sopenharmony_ci	struct renesas_usbhs_driver_pipe_config *pipe_config =
5088c2ecf20Sopenharmony_ci					usbhsp_get_pipe_config(priv, pipe_num);
5098c2ecf20Sopenharmony_ci	u16 dblb = pipe_config->double_buf ? DBLB : 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (devsel > 0xA) {
5128c2ecf20Sopenharmony_ci		struct device *dev = usbhs_priv_to_dev(priv);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		dev_err(dev, "devsel error %d\n", devsel);
5158c2ecf20Sopenharmony_ci
5168c2ecf20Sopenharmony_ci		devsel = 0;
5178c2ecf20Sopenharmony_ci	}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	usbhsp_pipe_barrier(pipe);
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	pipe->maxp = maxp;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	usbhsp_pipe_select(pipe);
5248c2ecf20Sopenharmony_ci	usbhsp_pipe_maxp_set(pipe, 0xFFFF,
5258c2ecf20Sopenharmony_ci			     (devsel << 12) |
5268c2ecf20Sopenharmony_ci			     maxp);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (!usbhs_pipe_is_dcp(pipe))
5298c2ecf20Sopenharmony_ci		usbhsp_pipe_cfg_set(pipe,  0x000F | DBLB, epnum | dblb);
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci/*
5338c2ecf20Sopenharmony_ci *		pipe control
5348c2ecf20Sopenharmony_ci */
5358c2ecf20Sopenharmony_ciint usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	/*
5388c2ecf20Sopenharmony_ci	 * see
5398c2ecf20Sopenharmony_ci	 *	usbhs_pipe_config_update()
5408c2ecf20Sopenharmony_ci	 *	usbhs_dcp_malloc()
5418c2ecf20Sopenharmony_ci	 */
5428c2ecf20Sopenharmony_ci	return pipe->maxp;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ciint usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	return usbhsp_flags_has(pipe, IS_DIR_IN);
5488c2ecf20Sopenharmony_ci}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ciint usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
5518c2ecf20Sopenharmony_ci{
5528c2ecf20Sopenharmony_ci	return usbhsp_flags_has(pipe, IS_DIR_HOST);
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ciint usbhs_pipe_is_running(struct usbhs_pipe *pipe)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	return usbhsp_flags_has(pipe, IS_RUNNING);
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_civoid usbhs_pipe_running(struct usbhs_pipe *pipe, int running)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	if (running)
5638c2ecf20Sopenharmony_ci		usbhsp_flags_set(pipe, IS_RUNNING);
5648c2ecf20Sopenharmony_ci	else
5658c2ecf20Sopenharmony_ci		usbhsp_flags_clr(pipe, IS_RUNNING);
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_civoid usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	u16 mask = (SQCLR | SQSET);
5718c2ecf20Sopenharmony_ci	u16 val;
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	/*
5748c2ecf20Sopenharmony_ci	 * sequence
5758c2ecf20Sopenharmony_ci	 *  0  : data0
5768c2ecf20Sopenharmony_ci	 *  1  : data1
5778c2ecf20Sopenharmony_ci	 *  -1 : no change
5788c2ecf20Sopenharmony_ci	 */
5798c2ecf20Sopenharmony_ci	switch (sequence) {
5808c2ecf20Sopenharmony_ci	case 0:
5818c2ecf20Sopenharmony_ci		val = SQCLR;
5828c2ecf20Sopenharmony_ci		break;
5838c2ecf20Sopenharmony_ci	case 1:
5848c2ecf20Sopenharmony_ci		val = SQSET;
5858c2ecf20Sopenharmony_ci		break;
5868c2ecf20Sopenharmony_ci	default:
5878c2ecf20Sopenharmony_ci		return;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	usbhsp_pipectrl_set(pipe, mask, val);
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int usbhs_pipe_get_data_sequence(struct usbhs_pipe *pipe)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	return !!(usbhsp_pipectrl_get(pipe) & SQMON);
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_civoid usbhs_pipe_clear(struct usbhs_pipe *pipe)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe)) {
6018c2ecf20Sopenharmony_ci		usbhs_fifo_clear_dcp(pipe);
6028c2ecf20Sopenharmony_ci	} else {
6038c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, ACLRM, ACLRM);
6048c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, ACLRM, 0);
6058c2ecf20Sopenharmony_ci	}
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci/* Should call usbhsp_pipe_select() before */
6098c2ecf20Sopenharmony_civoid usbhs_pipe_clear_without_sequence(struct usbhs_pipe *pipe,
6108c2ecf20Sopenharmony_ci				       int needs_bfre, int bfre_enable)
6118c2ecf20Sopenharmony_ci{
6128c2ecf20Sopenharmony_ci	int sequence;
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	usbhsp_pipe_select(pipe);
6158c2ecf20Sopenharmony_ci	sequence = usbhs_pipe_get_data_sequence(pipe);
6168c2ecf20Sopenharmony_ci	if (needs_bfre)
6178c2ecf20Sopenharmony_ci		usbhsp_pipe_cfg_set(pipe, BFRE, bfre_enable ? BFRE : 0);
6188c2ecf20Sopenharmony_ci	usbhs_pipe_clear(pipe);
6198c2ecf20Sopenharmony_ci	usbhs_pipe_data_sequence(pipe, sequence);
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_civoid usbhs_pipe_config_change_bfre(struct usbhs_pipe *pipe, int enable)
6238c2ecf20Sopenharmony_ci{
6248c2ecf20Sopenharmony_ci	if (usbhs_pipe_is_dcp(pipe))
6258c2ecf20Sopenharmony_ci		return;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	usbhsp_pipe_select(pipe);
6288c2ecf20Sopenharmony_ci	/* check if the driver needs to change the BFRE value */
6298c2ecf20Sopenharmony_ci	if (!(enable ^ !!(usbhsp_pipe_cfg_get(pipe) & BFRE)))
6308c2ecf20Sopenharmony_ci		return;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	usbhs_pipe_clear_without_sequence(pipe, 1, enable);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	struct usbhs_pipe *pos, *pipe;
6388c2ecf20Sopenharmony_ci	int i;
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_ci	/*
6418c2ecf20Sopenharmony_ci	 * find target pipe
6428c2ecf20Sopenharmony_ci	 */
6438c2ecf20Sopenharmony_ci	pipe = NULL;
6448c2ecf20Sopenharmony_ci	usbhs_for_each_pipe_with_dcp(pos, priv, i) {
6458c2ecf20Sopenharmony_ci		if (!usbhs_pipe_type_is(pos, type))
6468c2ecf20Sopenharmony_ci			continue;
6478c2ecf20Sopenharmony_ci		if (usbhsp_flags_has(pos, IS_USED))
6488c2ecf20Sopenharmony_ci			continue;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci		pipe = pos;
6518c2ecf20Sopenharmony_ci		break;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (!pipe)
6558c2ecf20Sopenharmony_ci		return NULL;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/*
6588c2ecf20Sopenharmony_ci	 * initialize pipe flags
6598c2ecf20Sopenharmony_ci	 */
6608c2ecf20Sopenharmony_ci	usbhsp_flags_init(pipe);
6618c2ecf20Sopenharmony_ci	usbhsp_flags_set(pipe, IS_USED);
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	return pipe;
6648c2ecf20Sopenharmony_ci}
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_cistatic void usbhsp_put_pipe(struct usbhs_pipe *pipe)
6678c2ecf20Sopenharmony_ci{
6688c2ecf20Sopenharmony_ci	usbhsp_flags_init(pipe);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_civoid usbhs_pipe_init(struct usbhs_priv *priv,
6728c2ecf20Sopenharmony_ci		     int (*dma_map_ctrl)(struct device *dma_dev,
6738c2ecf20Sopenharmony_ci					 struct usbhs_pkt *pkt, int map))
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
6768c2ecf20Sopenharmony_ci	struct usbhs_pipe *pipe;
6778c2ecf20Sopenharmony_ci	int i;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
6808c2ecf20Sopenharmony_ci		usbhsp_flags_init(pipe);
6818c2ecf20Sopenharmony_ci		pipe->fifo = NULL;
6828c2ecf20Sopenharmony_ci		pipe->mod_private = NULL;
6838c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&pipe->list);
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci		/* pipe force init */
6868c2ecf20Sopenharmony_ci		usbhs_pipe_clear(pipe);
6878c2ecf20Sopenharmony_ci	}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	info->dma_map_ctrl = dma_map_ctrl;
6908c2ecf20Sopenharmony_ci}
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_cistruct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
6938c2ecf20Sopenharmony_ci				     int endpoint_type,
6948c2ecf20Sopenharmony_ci				     int dir_in)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	struct device *dev = usbhs_priv_to_dev(priv);
6978c2ecf20Sopenharmony_ci	struct usbhs_pipe *pipe;
6988c2ecf20Sopenharmony_ci	int is_host = usbhs_mod_is_host(priv);
6998c2ecf20Sopenharmony_ci	int ret;
7008c2ecf20Sopenharmony_ci	u16 pipecfg, pipebuf;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	pipe = usbhsp_get_pipe(priv, endpoint_type);
7038c2ecf20Sopenharmony_ci	if (!pipe) {
7048c2ecf20Sopenharmony_ci		dev_err(dev, "can't get pipe (%s)\n",
7058c2ecf20Sopenharmony_ci			usbhsp_pipe_name[endpoint_type]);
7068c2ecf20Sopenharmony_ci		return NULL;
7078c2ecf20Sopenharmony_ci	}
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pipe->list);
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	usbhs_pipe_disable(pipe);
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci	/* make sure pipe is not busy */
7148c2ecf20Sopenharmony_ci	ret = usbhsp_pipe_barrier(pipe);
7158c2ecf20Sopenharmony_ci	if (ret < 0) {
7168c2ecf20Sopenharmony_ci		dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe));
7178c2ecf20Sopenharmony_ci		return NULL;
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) {
7218c2ecf20Sopenharmony_ci		dev_err(dev, "can't setup pipe\n");
7228c2ecf20Sopenharmony_ci		return NULL;
7238c2ecf20Sopenharmony_ci	}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	pipebuf  = usbhsp_setup_pipebuff(pipe);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	usbhsp_pipe_select(pipe);
7288c2ecf20Sopenharmony_ci	usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg);
7298c2ecf20Sopenharmony_ci	usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf);
7308c2ecf20Sopenharmony_ci	usbhs_pipe_clear(pipe);
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	usbhs_pipe_sequence_data0(pipe);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	dev_dbg(dev, "enable pipe %d : %s (%s)\n",
7358c2ecf20Sopenharmony_ci		usbhs_pipe_number(pipe),
7368c2ecf20Sopenharmony_ci		usbhs_pipe_name(pipe),
7378c2ecf20Sopenharmony_ci		usbhs_pipe_is_dir_in(pipe) ? "in" : "out");
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	/*
7408c2ecf20Sopenharmony_ci	 * epnum / maxp are still not set to this pipe.
7418c2ecf20Sopenharmony_ci	 * call usbhs_pipe_config_update() after this function !!
7428c2ecf20Sopenharmony_ci	 */
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	return pipe;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_civoid usbhs_pipe_free(struct usbhs_pipe *pipe)
7488c2ecf20Sopenharmony_ci{
7498c2ecf20Sopenharmony_ci	usbhsp_pipe_select(pipe);
7508c2ecf20Sopenharmony_ci	usbhsp_pipe_cfg_set(pipe, 0xFFFF, 0);
7518c2ecf20Sopenharmony_ci	usbhsp_put_pipe(pipe);
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_civoid usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo)
7558c2ecf20Sopenharmony_ci{
7568c2ecf20Sopenharmony_ci	if (pipe->fifo)
7578c2ecf20Sopenharmony_ci		pipe->fifo->pipe = NULL;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	pipe->fifo = fifo;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (fifo)
7628c2ecf20Sopenharmony_ci		fifo->pipe = pipe;
7638c2ecf20Sopenharmony_ci}
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci/*
7678c2ecf20Sopenharmony_ci *		dcp control
7688c2ecf20Sopenharmony_ci */
7698c2ecf20Sopenharmony_cistruct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv)
7708c2ecf20Sopenharmony_ci{
7718c2ecf20Sopenharmony_ci	struct usbhs_pipe *pipe;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	pipe = usbhsp_get_pipe(priv, USB_ENDPOINT_XFER_CONTROL);
7748c2ecf20Sopenharmony_ci	if (!pipe)
7758c2ecf20Sopenharmony_ci		return NULL;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pipe->list);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	/*
7808c2ecf20Sopenharmony_ci	 * call usbhs_pipe_config_update() after this function !!
7818c2ecf20Sopenharmony_ci	 */
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	return pipe;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_civoid usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe)
7878c2ecf20Sopenharmony_ci{
7888c2ecf20Sopenharmony_ci	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	WARN_ON(!usbhs_pipe_is_dcp(pipe));
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	usbhs_pipe_enable(pipe);
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	if (!usbhs_mod_is_host(priv)) /* funconly */
7958c2ecf20Sopenharmony_ci		usbhsp_pipectrl_set(pipe, CCPL, CCPL);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_civoid usbhs_dcp_dir_for_host(struct usbhs_pipe *pipe, int dir_out)
7998c2ecf20Sopenharmony_ci{
8008c2ecf20Sopenharmony_ci	usbhsp_pipe_cfg_set(pipe, DIR_OUT,
8018c2ecf20Sopenharmony_ci			    dir_out ? DIR_OUT : 0);
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci/*
8058c2ecf20Sopenharmony_ci *		pipe module function
8068c2ecf20Sopenharmony_ci */
8078c2ecf20Sopenharmony_ciint usbhs_pipe_probe(struct usbhs_priv *priv)
8088c2ecf20Sopenharmony_ci{
8098c2ecf20Sopenharmony_ci	struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
8108c2ecf20Sopenharmony_ci	struct usbhs_pipe *pipe;
8118c2ecf20Sopenharmony_ci	struct device *dev = usbhs_priv_to_dev(priv);
8128c2ecf20Sopenharmony_ci	struct renesas_usbhs_driver_pipe_config *pipe_configs =
8138c2ecf20Sopenharmony_ci					usbhs_get_dparam(priv, pipe_configs);
8148c2ecf20Sopenharmony_ci	int pipe_size = usbhs_get_dparam(priv, pipe_size);
8158c2ecf20Sopenharmony_ci	int i;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	/* This driver expects 1st pipe is DCP */
8188c2ecf20Sopenharmony_ci	if (pipe_configs[0].type != USB_ENDPOINT_XFER_CONTROL) {
8198c2ecf20Sopenharmony_ci		dev_err(dev, "1st PIPE is not DCP\n");
8208c2ecf20Sopenharmony_ci		return -EINVAL;
8218c2ecf20Sopenharmony_ci	}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_ci	info->pipe = kcalloc(pipe_size, sizeof(struct usbhs_pipe),
8248c2ecf20Sopenharmony_ci			     GFP_KERNEL);
8258c2ecf20Sopenharmony_ci	if (!info->pipe)
8268c2ecf20Sopenharmony_ci		return -ENOMEM;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	info->size = pipe_size;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	/*
8318c2ecf20Sopenharmony_ci	 * init pipe
8328c2ecf20Sopenharmony_ci	 */
8338c2ecf20Sopenharmony_ci	usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
8348c2ecf20Sopenharmony_ci		pipe->priv = priv;
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci		usbhs_pipe_type(pipe) =
8378c2ecf20Sopenharmony_ci			pipe_configs[i].type & USB_ENDPOINT_XFERTYPE_MASK;
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci		dev_dbg(dev, "pipe %x\t: %s\n",
8408c2ecf20Sopenharmony_ci			i, usbhsp_pipe_name[pipe_configs[i].type]);
8418c2ecf20Sopenharmony_ci	}
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	return 0;
8448c2ecf20Sopenharmony_ci}
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_civoid usbhs_pipe_remove(struct usbhs_priv *priv)
8478c2ecf20Sopenharmony_ci{
8488c2ecf20Sopenharmony_ci	struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	kfree(info->pipe);
8518c2ecf20Sopenharmony_ci}
852