summaryrefslogtreecommitdiffstats
path: root/drivers/phy/marvell/comphy_mux.c
blob: 053870231759840600f9b3d70477af17cdda51c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2015-2016 Marvell International Ltd.
 */

#include <common.h>
#include <asm/io.h>

#include "comphy.h"
#include "comphy_hpipe.h"

/*
 * comphy_mux_check_config()
 * description: this function passes over the COMPHY lanes and check if the type
 *              is valid for specific lane. If the type is not valid,
 *              the function update the struct and set the type of the lane as
 *              PHY_TYPE_UNCONNECTED
 */
static void comphy_mux_check_config(struct comphy_mux_data *mux_data,
		struct comphy_map *comphy_map_data, int comphy_max_lanes)
{
	struct comphy_mux_options *mux_opt;
	int lane, opt, valid;

	debug_enter();

	for (lane = 0; lane < comphy_max_lanes;
	     lane++, comphy_map_data++, mux_data++) {
		/* Don't check ignored COMPHYs */
		if (comphy_map_data->type == PHY_TYPE_IGNORE)
			continue;

		mux_opt = mux_data->mux_values;
		for (opt = 0, valid = 0; opt < mux_data->max_lane_values;
		     opt++, mux_opt++) {
			if (mux_opt->type == comphy_map_data->type) {
				valid = 1;
				break;
			}
		}
		if (valid == 0) {
			debug("lane number %d, had invalid type %d\n",
			      lane, comphy_map_data->type);
			debug("set lane %d as type %d\n", lane,
			      PHY_TYPE_UNCONNECTED);
			comphy_map_data->type = PHY_TYPE_UNCONNECTED;
		} else {
			debug("lane number %d, has type %d\n",
			      lane, comphy_map_data->type);
		}
	}

	debug_exit();
}

static u32 comphy_mux_get_mux_value(struct comphy_mux_data *mux_data,
				    u32 type, int lane)
{
	struct comphy_mux_options *mux_opt;
	int opt;
	u32 value = 0;

	debug_enter();

	mux_opt = mux_data->mux_values;
	for (opt = 0 ; opt < mux_data->max_lane_values; opt++, mux_opt++) {
		if (mux_opt->type == type) {
			value = mux_opt->mux_value;
			break;
		}
	}

	debug_exit();

	return value;
}

static void comphy_mux_reg_write(struct comphy_mux_data *mux_data,
				 struct comphy_map *comphy_map_data,
				 int comphy_max_lanes,
				 void __iomem *selector_base, u32 bitcount)
{
	u32 lane, value, offset, mask;

	debug_enter();

	for (lane = 0; lane < comphy_max_lanes;
	     lane++, comphy_map_data++, mux_data++) {
		if (comphy_map_data->type == PHY_TYPE_IGNORE)
			continue;

		offset = lane * bitcount;
		mask = (((1 << bitcount) - 1) << offset);
		value = (comphy_mux_get_mux_value(mux_data,
						  comphy_map_data->type,
						  lane) << offset);
		reg_set(selector_base, value, mask);
	}

	debug_exit();
}

void comphy_mux_init(struct chip_serdes_phy_config *chip_cfg,
		     struct comphy_map *comphy_map_data,
		     void __iomem *selector_base)
{
	struct comphy_mux_data *mux_data;
	u32 mux_bitcount;
	u32 comphy_max_lanes;

	debug_enter();

	comphy_max_lanes = chip_cfg->comphy_lanes_count;
	mux_data = chip_cfg->mux_data;
	mux_bitcount = chip_cfg->comphy_mux_bitcount;

	/* check if the configuration is valid */
	comphy_mux_check_config(mux_data, comphy_map_data, comphy_max_lanes);
	/* Init COMPHY selectors */
	comphy_mux_reg_write(mux_data, comphy_map_data, comphy_max_lanes,
			     selector_base, mux_bitcount);

	debug_exit();
}