summaryrefslogtreecommitdiffstats
path: root/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c')
-rw-r--r--drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c358
1 files changed, 358 insertions, 0 deletions
diff --git a/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
new file mode 100644
index 0000000..60b6f35
--- /dev/null
+++ b/drivers/staging/westbridge/astoria/api/src/cyaslep2pep.c
@@ -0,0 +1,358 @@
+/* Cypress West Bridge API source file (cyaslep2pep.c)
+## ===========================
+## Copyright (C) 2010 Cypress Semiconductor
+##
+## This program is free software; you can redistribute it and/or
+## modify it under the terms of the GNU General Public License
+## as published by the Free Software Foundation; either version 2
+## of the License, or (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin Street, Fifth Floor
+## Boston, MA 02110-1301, USA.
+## ===========================
+*/
+
+#include "../../include/linux/westbridge/cyashal.h"
+#include "../../include/linux/westbridge/cyasusb.h"
+#include "../../include/linux/westbridge/cyaserr.h"
+#include "../../include/linux/westbridge/cyaslowlevel.h"
+#include "../../include/linux/westbridge/cyasdma.h"
+
+typedef enum cy_as_physical_endpoint_state {
+ cy_as_e_p_free,
+ cy_as_e_p_in,
+ cy_as_e_p_out,
+ cy_as_e_p_iso_in,
+ cy_as_e_p_iso_out
+} cy_as_physical_endpoint_state;
+
+
+/*
+* This map is used to map an index between 1 and 10
+* to a logical endpoint number. This is used to map
+* LEP register indexes into actual EP numbers.
+*/
+static cy_as_end_point_number_t end_point_map[] = {
+ 3, 5, 7, 9, 10, 11, 12, 13, 14, 15 };
+
+#define CY_AS_EPCFG_1024 (1 << 3)
+#define CY_AS_EPCFG_DBL (0x02)
+#define CY_AS_EPCFG_TRIPLE (0x03)
+#define CY_AS_EPCFG_QUAD (0x00)
+
+/*
+ * NB: This table contains the register values for PEP1
+ * and PEP3. PEP2 and PEP4 only have a bit to change the
+ * direction of the PEP and therefre are not represented
+ * in this table.
+ */
+static uint8_t pep_register_values[12][4] = {
+ /* Bit 1:0 buffering, 0 = quad, 2 = double, 3 = triple */
+ /* Bit 3 size, 0 = 512, 1 = 1024 */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL,
+ },/* Config 1 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_QUAD,
+ }, /* Config 2 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL | CY_AS_EPCFG_1024,
+ },/* Config 3 - PEP1 (2 * 512), PEP2 (2 * 512),
+ * PEP3 (2 * 1024), PEP4(N/A) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_DBL,
+ },/* Config 4 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_QUAD,
+ },/* Config 5 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_QUAD,
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ },/* Config 6 - PEP1 (4 * 512), PEP2 (N/A),
+ * PEP3 (2 * 1024), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_DBL,
+ },/* Config 7 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (2 * 512), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_QUAD,
+ },/* Config 8 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (4 * 512), PEP4 (N/A) */
+ {
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ CY_AS_EPCFG_1024 | CY_AS_EPCFG_DBL,
+ },/* Config 9 - PEP1 (2 * 1024), PEP2 (N/A),
+ * PEP3 (2 * 1024), PEP4 (N/A)*/
+ {
+ CY_AS_EPCFG_TRIPLE,
+ CY_AS_EPCFG_TRIPLE,
+ },/* Config 10 - PEP1 (3 * 512), PEP2 (N/A),
+ * PEP3 (3 * 512), PEP4 (2 * 512)*/
+ {
+ CY_AS_EPCFG_TRIPLE | CY_AS_EPCFG_1024,
+ CY_AS_EPCFG_DBL,
+ },/* Config 11 - PEP1 (3 * 1024), PEP2 (N/A),
+ * PEP3 (N/A), PEP4 (2 * 512) */
+ {
+ CY_AS_EPCFG_QUAD | CY_AS_EPCFG_1024,
+ CY_AS_EPCFG_DBL,
+ },/* Config 12 - PEP1 (4 * 1024), PEP2 (N/A),
+ * PEP3 (N/A), PEP4 (N/A) */
+};
+
+static cy_as_return_status_t
+find_endpoint_directions(cy_as_device *dev_p,
+ cy_as_physical_endpoint_state epstate[4])
+{
+ int i;
+ cy_as_physical_endpoint_state desired;
+
+ /*
+ * note, there is no error checking here becuase
+ * ISO error checking happens when the API is called.
+ */
+ for (i = 0; i < 10; i++) {
+ int epno = end_point_map[i];
+ if (dev_p->usb_config[epno].enabled) {
+ int pep = dev_p->usb_config[epno].physical;
+ if (dev_p->usb_config[epno].type == cy_as_usb_iso) {
+ /*
+ * marking this as an ISO endpoint, removes the
+ * physical EP from consideration when
+ * mapping the remaining E_ps.
+ */
+ if (dev_p->usb_config[epno].dir == cy_as_usb_in)
+ desired = cy_as_e_p_iso_in;
+ else
+ desired = cy_as_e_p_iso_out;
+ } else {
+ if (dev_p->usb_config[epno].dir == cy_as_usb_in)
+ desired = cy_as_e_p_in;
+ else
+ desired = cy_as_e_p_out;
+ }
+
+ /*
+ * NB: Note the API calls insure that an ISO endpoint
+ * has a physical and logical EP number that are the
+ * same, therefore this condition is not enforced here.
+ */
+ if (epstate[pep - 1] !=
+ cy_as_e_p_free && epstate[pep - 1] != desired)
+ return CY_AS_ERROR_INVALID_CONFIGURATION;
+
+ epstate[pep - 1] = desired;
+ }
+ }
+
+ /*
+ * create the EP1 config values directly.
+ * both EP1OUT and EP1IN are invalid by default.
+ */
+ dev_p->usb_ep1cfg[0] = 0;
+ dev_p->usb_ep1cfg[1] = 0;
+ if (dev_p->usb_config[1].enabled) {
+ if ((dev_p->usb_config[1].dir == cy_as_usb_out) ||
+ (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
+ /* Set the valid bit and type field. */
+ dev_p->usb_ep1cfg[0] = (1 << 7);
+ if (dev_p->usb_config[1].type == cy_as_usb_bulk)
+ dev_p->usb_ep1cfg[0] |= (2 << 4);
+ else
+ dev_p->usb_ep1cfg[0] |= (3 << 4);
+ }
+
+ if ((dev_p->usb_config[1].dir == cy_as_usb_in) ||
+ (dev_p->usb_config[1].dir == cy_as_usb_in_out)) {
+ /* Set the valid bit and type field. */
+ dev_p->usb_ep1cfg[1] = (1 << 7);
+ if (dev_p->usb_config[1].type == cy_as_usb_bulk)
+ dev_p->usb_ep1cfg[1] |= (2 << 4);
+ else
+ dev_p->usb_ep1cfg[1] |= (3 << 4);
+ }
+ }
+
+ return CY_AS_ERROR_SUCCESS;
+}
+
+static void
+create_register_settings(cy_as_device *dev_p,
+ cy_as_physical_endpoint_state epstate[4])
+{
+ int i;
+ uint8_t v;
+
+ for (i = 0; i < 4; i++) {
+ if (i == 0) {
+ /* Start with the values that specify size */
+ dev_p->usb_pepcfg[i] =
+ pep_register_values
+ [dev_p->usb_phy_config - 1][0];
+ } else if (i == 2) {
+ /* Start with the values that specify size */
+ dev_p->usb_pepcfg[i] =
+ pep_register_values
+ [dev_p->usb_phy_config - 1][1];
+ } else
+ dev_p->usb_pepcfg[i] = 0;
+
+ /* Adjust direction if it is in */
+ if (epstate[i] == cy_as_e_p_iso_in ||
+ epstate[i] == cy_as_e_p_in)
+ dev_p->usb_pepcfg[i] |= (1 << 6);
+ }
+
+ /* Configure the logical EP registers */
+ for (i = 0; i < 10; i++) {
+ int val;
+ int epnum = end_point_map[i];
+
+ v = 0x10; /* PEP 1, Bulk Endpoint, EP not valid */
+ if (dev_p->usb_config[epnum].enabled) {
+ v |= (1 << 7); /* Enabled */
+
+ val = dev_p->usb_config[epnum].physical - 1;
+ cy_as_hal_assert(val >= 0 && val <= 3);
+ v |= (val << 5);
+
+ switch (dev_p->usb_config[epnum].type) {
+ case cy_as_usb_bulk:
+ val = 2;
+ break;
+ case cy_as_usb_int:
+ val = 3;
+ break;
+ case cy_as_usb_iso:
+ val = 1;
+ break;
+ default:
+ cy_as_hal_assert(cy_false);
+ break;
+ }
+ v |= (val << 3);
+ }
+
+ dev_p->usb_lepcfg[i] = v;
+ }
+}
+
+
+cy_as_return_status_t
+cy_as_usb_map_logical2_physical(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret;
+
+ /* Physical EPs 3 5 7 9 respectively in the array */
+ cy_as_physical_endpoint_state epstate[4] = {
+ cy_as_e_p_free, cy_as_e_p_free,
+ cy_as_e_p_free, cy_as_e_p_free };
+
+ /* Find the direction for the endpoints */
+ ret = find_endpoint_directions(dev_p, epstate);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ return ret;
+
+ /*
+ * now create the register settings based on the given
+ * assigned of logical E_ps to physical endpoints.
+ */
+ create_register_settings(dev_p, epstate);
+
+ return ret;
+}
+
+static uint16_t
+get_max_dma_size(cy_as_device *dev_p, cy_as_end_point_number_t ep)
+{
+ uint16_t size = dev_p->usb_config[ep].size;
+
+ if (size == 0) {
+ switch (dev_p->usb_config[ep].type) {
+ case cy_as_usb_control:
+ size = 64;
+ break;
+
+ case cy_as_usb_bulk:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 512 : 64;
+ break;
+
+ case cy_as_usb_int:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 1024 : 64;
+ break;
+
+ case cy_as_usb_iso:
+ size = cy_as_device_is_usb_high_speed(dev_p) ?
+ 1024 : 1023;
+ break;
+ }
+ }
+
+ return size;
+}
+
+cy_as_return_status_t
+cy_as_usb_set_dma_sizes(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t i;
+
+ for (i = 0; i < 10; i++) {
+ cy_as_usb_end_point_config *config_p =
+ &dev_p->usb_config[end_point_map[i]];
+ if (config_p->enabled) {
+ ret = cy_as_dma_set_max_dma_size(dev_p,
+ end_point_map[i],
+ get_max_dma_size(dev_p, end_point_map[i]));
+ if (ret != CY_AS_ERROR_SUCCESS)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+cy_as_return_status_t
+cy_as_usb_setup_dma(cy_as_device *dev_p)
+{
+ cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
+ uint32_t i;
+
+ for (i = 0; i < 10; i++) {
+ cy_as_usb_end_point_config *config_p =
+ &dev_p->usb_config[end_point_map[i]];
+ if (config_p->enabled) {
+ /* Map the endpoint direction to the DMA direction */
+ cy_as_dma_direction dir = cy_as_direction_out;
+ if (config_p->dir == cy_as_usb_in)
+ dir = cy_as_direction_in;
+
+ ret = cy_as_dma_enable_end_point(dev_p,
+ end_point_map[i], cy_true, dir);
+ if (ret != CY_AS_ERROR_SUCCESS)
+ break;
+ }
+ }
+
+ return ret;
+}
OpenPOWER on IntegriCloud