[centec]: Add centec arm64 architecture support for E530 (#4641)

summary of E530 platfrom:
 - CPU: CTC5236, arm64
 - LAN switch chip set: CENTEC CTC7132 (TsingMa). TsingMa is a purpose built device to address the challenge in the recent network evolution such as Cloud computing. CTC7132 provides 440Gbps I/O bandwidth and 400Gcore bandwidth, the CTC7132 family combines a feature-rich switch core and an embedded ARM A53 CPU Core running at 800MHz/1.2GHz. CTC7132 supports a variety of port configurations, such as QSGMII and USXGMII-M, providing full-rate port capability from 100M to 100G.
- device E530-48T4X: 48 * 10/100/1000 Base-T Ports, 4 * 10GE SFP+ Ports.
- device E530-24X2C: 24 * 10 GE SFP+ Ports, 2 * 100GE QSFP28 Ports.

add new files in three directories:
device/centec/arm64-centec_e530_24x2c-r0
device/centec/arm64-centec_e530_48t4x_p-r0
platform/centec-arm64

Co-authored-by: taocy <taocy2@centecnetworks.com>
Co-authored-by: Gu Xianghong <gxh2001757@163.com>
Co-authored-by: shil <shil@centecnetworks.com>
This commit is contained in:
taochengyi 2020-08-06 18:16:11 +08:00 committed by GitHub
parent 9e100257d0
commit 08f3b9720b
No account linked to committer's email address
130 changed files with 26369 additions and 171 deletions

View File

@ -187,6 +187,10 @@ if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then
sudo chmod +x $FILESYSTEM_ROOT/etc/initramfs-tools/hooks/uboot-utils
cat files/initramfs-tools/modules.arm | sudo tee -a $FILESYSTEM_ROOT/etc/initramfs-tools/modules > /dev/null
fi
# Update initramfs for load platform specific modules
if [ -f platform/$CONFIGURED_PLATFORM/modules ]; then
cat platform/$CONFIGURED_PLATFORM/modules | sudo tee -a $FILESYSTEM_ROOT/etc/initramfs-tools/modules > /dev/null
fi
## Install docker
echo '[INFO] Install docker'

View File

@ -0,0 +1,70 @@
{# Default values which will be used if no actual configura available #}
{% set default_cable = '40m' %}
{% set default_ports_num = 54 -%}
{# Port configuration to cable length look-up table #}
{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #}
{# Roles described in the minigraph #}
{% set ports2cable = {
'torrouter_server' : '5m',
'leafrouter_torrouter' : '40m',
'spinerouter_leafrouter' : '300m'
}
%}
{%- macro cable_length(port_name) -%}
{%- set cable_len = [] -%}
{%- for local_port in DEVICE_NEIGHBOR -%}
{%- if local_port == port_name -%}
{%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
{%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
{%- set neighbor_role = neighbor.type -%}
{%- set roles1 = switch_role + '_' + neighbor_role %}
{%- set roles2 = neighbor_role + '_' + switch_role -%}
{%- set roles1 = roles1 | lower -%}
{%- set roles2 = roles2 | lower -%}
{%- if roles1 in ports2cable -%}
{%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%}
{%- elif roles2 in ports2cable -%}
{%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- if cable_len -%}
{{ cable_len.0 }}
{%- else -%}
{{ default_cable }}
{%- endif -%}
{% endmacro %}
{%- if DEVICE_METADATA is defined %}
{%- set switch_role = DEVICE_METADATA['localhost']['type'] %}
{%- endif -%}
{# Generate list of ports if not defined #}
{% if PORT is not defined %}
{% set PORT = [] %}
{% for port_idx in range(1,default_ports_num+1) %}
{% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %}
{% endfor %}
{% endif -%}
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"CABLE_LENGTH": {
"AZURE": {
{% for port in PORT %}
{% set cable = cable_length(port) -%}
"{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %}
{% endfor %}
}
}
}

View File

@ -0,0 +1,21 @@
# PG lossless profiles.
# speed cable size xon xoff threshold
1000 5m 34816 18432 16384 0
10000 5m 34816 18432 16384 0
25000 5m 34816 18432 16384 0
40000 5m 34816 18432 16384 0
50000 5m 34816 18432 16384 0
100000 5m 36864 18432 18432 0
1000 40m 36864 18432 18432 0
10000 40m 36864 18432 18432 0
25000 40m 39936 18432 21504 0
40000 40m 41984 18432 23552 0
50000 40m 41984 18432 23552 0
100000 40m 54272 18432 35840 0
1000 300m 49152 18432 30720 0
10000 300m 49152 18432 30720 0
25000 300m 71680 18432 53248 0
40000 300m 94208 18432 75776 0
50000 300m 94208 18432 75776 0
100000 300m 184320 18432 165888 0

View File

@ -0,0 +1,27 @@
# name lanes alias speed
Ethernet1 0 eth-0-1 10000
Ethernet2 1 eth-0-2 10000
Ethernet3 2 eth-0-3 10000
Ethernet4 3 eth-0-4 10000
Ethernet5 8 eth-0-5 10000
Ethernet6 9 eth-0-6 10000
Ethernet7 10 eth-0-7 10000
Ethernet8 11 eth-0-8 10000
Ethernet9 20 eth-0-9 10000
Ethernet10 21 eth-0-10 10000
Ethernet11 22 eth-0-11 10000
Ethernet12 23 eth-0-12 10000
Ethernet13 12 eth-0-13 10000
Ethernet14 13 eth-0-14 10000
Ethernet15 14 eth-0-15 10000
Ethernet16 15 eth-0-16 10000
Ethernet17 24 eth-0-17 10000
Ethernet18 25 eth-0-18 10000
Ethernet19 26 eth-0-19 10000
Ethernet20 27 eth-0-20 10000
Ethernet21 28 eth-0-21 10000
Ethernet22 29 eth-0-22 10000
Ethernet23 30 eth-0-23 10000
Ethernet24 31 eth-0-24 10000
Ethernet25 61,60,63,62 eth-0-25 100000
Ethernet26 45,44,47,46 eth-0-26 100000

View File

@ -0,0 +1 @@
{%- include 'qos_config.j2' %}

View File

@ -0,0 +1,2 @@
SAI_INIT_CONFIG_FILE=/etc/centec/E530-24x2c-chip-profile.txt
SAI_HW_PORT_PROFILE_ID_CONFIG_FILE=/etc/centec/E530-24x2c-datapath-cfg.txt

View File

@ -0,0 +1 @@
E530-24x2c l2

View File

@ -0,0 +1 @@
# Configuration file generated by pwmconfig, changes will be lost

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
#############################################################################
# Centec E550-24X8Y2C
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
from sonic_eeprom import eeprom_tlvinfo
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/dev/mtd3"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,98 @@
#!/usr/bin/env python
#
# led_control.py
#
# Platform-specific LED control functionality for SONiC
#
try:
from sonic_led.led_control_base import LedControlBase
import syslog
from socket import *
from select import *
except ImportError, e:
raise ImportError(str(e) + " - required module not found")
def DBG_PRINT(str):
syslog.openlog("centec-led")
syslog.syslog(syslog.LOG_INFO, str)
syslog.closelog()
class LedControl(LedControlBase):
"""Platform specific LED control class"""
# Helper method to map SONiC port name to index
def _port_name_to_index(self, port_name):
# Strip "Ethernet" off port name
if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
return -1
port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
return port_idx
def _port_state_to_mode(self, port_idx, state):
if state == "up":
return self.LED_MODE_UP[0] if (port_idx < 25) else self.LED_MODE_UP[1]
else:
return self.LED_MODE_DOWN[0] if (port_idx < 25) else self.LED_MODE_DOWN[1]
def _port_led_mode_update(self, port_idx, ledMode):
with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file:
led_file.write(str(ledMode))
def _initSystemLed(self):
try:
with open(self.f_led.format("system"), 'w') as led_file:
led_file.write("1")
DBG_PRINT("init system led to normal")
with open(self.f_led.format("idn"), 'w') as led_file:
led_file.write("1")
DBG_PRINT("init idn led to off")
except IOError as e:
DBG_PRINT(str(e))
def _initPanelLed(self):
with open(self.f_led.format("port1"), 'r') as led_file:
shouldInit = (int(led_file.read()) == 0)
if shouldInit == True:
for idx in range(1, 27):
defmode = self._port_state_to_mode(idx, "down")
with open(self.f_led.format("port{}".format(idx)), 'w') as led_file:
led_file.write(str(defmode))
DBG_PRINT("init port{} led to mode={}".format(idx, defmode))
def _initDefaultConfig(self):
DBG_PRINT("start init led")
self._initSystemLed()
self._initPanelLed()
DBG_PRINT("init led done")
# Concrete implementation of port_link_state_change() method
def port_link_state_change(self, portname, state):
port_idx = self._port_name_to_index(portname)
ledMode = self._port_state_to_mode(port_idx, state)
with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file:
saveMode = int(led_file.read())
if ledMode == saveMode:
return
self._port_led_mode_update(port_idx, ledMode)
DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode))
# Constructor
def __init__(self):
self.SONIC_PORT_NAME_PREFIX = "Ethernet"
self.LED_MODE_UP = [11, 11]
self.LED_MODE_DOWN = [7, 7]
self.f_led = "/sys/class/leds/{}/brightness"
self._initDefaultConfig()

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python
#############################################################################
# Centec
#
# Module contains an implementation of SONiC PSU Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.psu_path = "/sys/class/psu/psu{}/"
self.psu_presence = "psu_presence"
self.psu_oper_status = "psu_status"
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
return 2
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined
by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is faulty
"""
if index is None:
return False
status = 0
try:
with open(self.psu_path.format(index) + self.psu_oper_status, 'r') as power_status:
status = int(power_status.read())
except IOError:
return False
return status == 1
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
if index is None:
return False
status = 0
try:
with open(self.psu_path.format(index) + self.psu_presence, 'r') as presence_status:
status = int(presence_status.read())
except IOError:
return False
return status == 1

View File

@ -0,0 +1,163 @@
#!/usr/bin/env python
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
from socket import *
from select import *
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
def DBG_PRINT(str):
print str + "\n"
SFP_STATUS_INSERTED = '1'
SFP_STATUS_REMOVED = '0'
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def sfp_base(self):
return self.SFP_BASE
@property
def qsfp_ports(self):
return range(25, self.PORTS_IN_BLOCK + 1)
@property
def port_to_eeprom_mapping(self):
return self.eeprom_mapping
def is_logical_port(self, port_name):
return True
def get_eeprom_data(self, port):
ret = None
port_num = self.get_logical_to_physical(port)[0]
if port_num < self.port_start or port_num > self.port_end:
return ret
if port_num < self.sfp_base:
return ret
try:
with open(self.eeprom_mapping[port_num], 'r') as eeprom_file:
ret = eeprom_file.read()
except IOError as e:
DBG_PRINT(str(e))
return ret
# todo
#def _get_port_eeprom_path(self, port_num, devid):
# pass
def __init__(self):
self.SONIC_PORT_NAME_PREFIX = "Ethernet"
self.PORT_START = 1
self.PORT_END = 26
self.SFP_BASE = 1
self.PORTS_IN_BLOCK = 26
self.logical = []
self.physical_to_logical = {}
self.logical_to_physical = {}
self.eeprom_mapping = {}
self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence"
self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable"
for x in range(self.port_start, self.sfp_base):
self.eeprom_mapping[x] = None
for x in range(self.sfp_base, self.port_end + 1):
self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(x - self.sfp_base + 1)
self.presence = {}
for x in range(self.sfp_base, self.port_end + 1):
self.presence[x] = False;
SfpUtilBase.__init__(self)
for x in range(self.sfp_base, self.port_end + 1):
self.logical.append('Ethernet' + str(x))
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
if port_num < self.sfp_base:
return False
try:
with open(self.f_sfp_present.format(port_num - self.sfp_base + 1), 'r') as sfp_file:
return 1 == int(sfp_file.read())
except IOError as e:
DBG_PRINT(str(e))
return False
def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def reset(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def read_porttab_mappings(self, porttabfile):
for x in range(self.sfp_base, self.port_end + 1):
self.logical_to_physical['Ethernet' + str(x)] = [x]
self.physical_to_logical[x] = ['Ethernet' + str(x)]
data = {'valid':0, 'last':0}
def get_transceiver_change_event(self, timeout=2000):
now = time.time()
port_dict = {}
if timeout < 1000:
timeout = 1000
timeout = (timeout) / float(1000) # Convert to secs
if now < (self.data['last'] + timeout) and self.data['valid']:
return True, {}
for x in range(self.sfp_base, self.port_end + 1):
presence = self.get_presence(x)
if presence != self.presence[x]:
self.presence[x] = presence
if presence:
port_dict[x] = SFP_STATUS_INSERTED
else:
port_dict[x] = SFP_STATUS_REMOVED
if bool(port_dict):
self.data['last'] = now
self.data['valid'] = 1
return True, port_dict
else:
time.sleep(0.5)
return True, {}

View File

@ -0,0 +1,70 @@
{# Default values which will be used if no actual configura available #}
{% set default_cable = '40m' %}
{% set default_ports_num = 54 -%}
{# Port configuration to cable length look-up table #}
{# Each record describes mapping of DUT (DUT port) role and neighbor role to cable length #}
{# Roles described in the minigraph #}
{% set ports2cable = {
'torrouter_server' : '5m',
'leafrouter_torrouter' : '40m',
'spinerouter_leafrouter' : '300m'
}
%}
{%- macro cable_length(port_name) -%}
{%- set cable_len = [] -%}
{%- for local_port in DEVICE_NEIGHBOR -%}
{%- if local_port == port_name -%}
{%- if DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
{%- set neighbor = DEVICE_NEIGHBOR_METADATA[DEVICE_NEIGHBOR[local_port].name] -%}
{%- set neighbor_role = neighbor.type -%}
{%- set roles1 = switch_role + '_' + neighbor_role %}
{%- set roles2 = neighbor_role + '_' + switch_role -%}
{%- set roles1 = roles1 | lower -%}
{%- set roles2 = roles2 | lower -%}
{%- if roles1 in ports2cable -%}
{%- if cable_len.append(ports2cable[roles1]) -%}{%- endif -%}
{%- elif roles2 in ports2cable -%}
{%- if cable_len.append(ports2cable[roles2]) -%}{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- if cable_len -%}
{{ cable_len.0 }}
{%- else -%}
{{ default_cable }}
{%- endif -%}
{% endmacro %}
{%- if DEVICE_METADATA is defined %}
{%- set switch_role = DEVICE_METADATA['localhost']['type'] %}
{%- endif -%}
{# Generate list of ports if not defined #}
{% if PORT is not defined %}
{% set PORT = [] %}
{% for port_idx in range(1,default_ports_num+1) %}
{% if PORT.append("Ethernet%d" % (port_idx)) %}{% endif %}
{% endfor %}
{% endif -%}
{% set port_names_list = [] %}
{% for port in PORT %}
{%- if port_names_list.append(port) %}{% endif %}
{% endfor %}
{% set port_names = port_names_list | join(',') -%}
{
"CABLE_LENGTH": {
"AZURE": {
{% for port in PORT %}
{% set cable = cable_length(port) -%}
"{{ port }}": "{{ cable }}"{%- if not loop.last -%},{% endif %}
{% endfor %}
}
}
}

View File

@ -0,0 +1,21 @@
# PG lossless profiles.
# speed cable size xon xoff threshold
1000 5m 34816 18432 16384 0
10000 5m 34816 18432 16384 0
25000 5m 34816 18432 16384 0
40000 5m 34816 18432 16384 0
50000 5m 34816 18432 16384 0
100000 5m 36864 18432 18432 0
1000 40m 36864 18432 18432 0
10000 40m 36864 18432 18432 0
25000 40m 39936 18432 21504 0
40000 40m 41984 18432 23552 0
50000 40m 41984 18432 23552 0
100000 40m 54272 18432 35840 0
1000 300m 49152 18432 30720 0
10000 300m 49152 18432 30720 0
25000 300m 71680 18432 53248 0
40000 300m 94208 18432 75776 0
50000 300m 94208 18432 75776 0
100000 300m 184320 18432 165888 0

View File

@ -0,0 +1,53 @@
# name lanes alias speed
Ethernet1 1 eth-0-1 1000
Ethernet2 0 eth-0-2 1000
Ethernet3 3 eth-0-3 1000
Ethernet4 2 eth-0-4 1000
Ethernet5 5 eth-0-5 1000
Ethernet6 4 eth-0-6 1000
Ethernet7 7 eth-0-7 1000
Ethernet8 6 eth-0-8 1000
Ethernet9 17 eth-0-9 1000
Ethernet10 16 eth-0-10 1000
Ethernet11 19 eth-0-11 1000
Ethernet12 18 eth-0-12 1000
Ethernet13 21 eth-0-13 1000
Ethernet14 20 eth-0-14 1000
Ethernet15 23 eth-0-15 1000
Ethernet16 22 eth-0-16 1000
Ethernet17 9 eth-0-17 1000
Ethernet18 8 eth-0-18 1000
Ethernet19 11 eth-0-19 1000
Ethernet20 10 eth-0-20 1000
Ethernet21 33 eth-0-21 1000
Ethernet22 32 eth-0-22 1000
Ethernet23 35 eth-0-23 1000
Ethernet24 34 eth-0-24 1000
Ethernet25 37 eth-0-25 1000
Ethernet26 36 eth-0-26 1000
Ethernet27 39 eth-0-27 1000
Ethernet28 38 eth-0-28 1000
Ethernet29 41 eth-0-29 1000
Ethernet30 40 eth-0-30 1000
Ethernet31 43 eth-0-31 1000
Ethernet32 42 eth-0-32 1000
Ethernet33 25 eth-0-33 1000
Ethernet34 24 eth-0-34 1000
Ethernet35 27 eth-0-35 1000
Ethernet36 26 eth-0-36 1000
Ethernet37 49 eth-0-37 1000
Ethernet38 48 eth-0-38 1000
Ethernet39 51 eth-0-39 1000
Ethernet40 50 eth-0-40 1000
Ethernet41 53 eth-0-41 1000
Ethernet42 52 eth-0-42 1000
Ethernet43 55 eth-0-43 1000
Ethernet44 54 eth-0-44 1000
Ethernet45 57 eth-0-45 1000
Ethernet46 56 eth-0-46 1000
Ethernet47 59 eth-0-47 1000
Ethernet48 58 eth-0-48 1000
Ethernet49 13 eth-0-49 10000
Ethernet50 12 eth-0-50 10000
Ethernet51 15 eth-0-51 10000
Ethernet52 14 eth-0-52 10000

View File

@ -0,0 +1 @@
{%- include 'qos_config.j2' %}

View File

@ -0,0 +1,2 @@
SAI_INIT_CONFIG_FILE=/etc/centec/E530-48t4x-p-chip-profile.txt
SAI_HW_PORT_PROFILE_ID_CONFIG_FILE=/etc/centec/E530-48t4x-p-datapath.txt

View File

@ -0,0 +1 @@
E530-48t4x-p l2

View File

@ -0,0 +1 @@
# Configuration file generated by pwmconfig, changes will be lost

View File

@ -0,0 +1,22 @@
#!/usr/bin/env python
#############################################################################
# Centec E550-24X8Y2C
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
from sonic_eeprom import eeprom_tlvinfo
except ImportError, e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = "/dev/mtd3"
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,98 @@
#!/usr/bin/env python
#
# led_control.py
#
# Platform-specific LED control functionality for SONiC
#
try:
from sonic_led.led_control_base import LedControlBase
import syslog
from socket import *
from select import *
except ImportError, e:
raise ImportError(str(e) + " - required module not found")
def DBG_PRINT(str):
syslog.openlog("centec-led")
syslog.syslog(syslog.LOG_INFO, str)
syslog.closelog()
class LedControl(LedControlBase):
"""Platform specific LED control class"""
# Helper method to map SONiC port name to index
def _port_name_to_index(self, port_name):
# Strip "Ethernet" off port name
if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
return -1
port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
return port_idx
def _port_state_to_mode(self, port_idx, state):
if state == "up":
return self.LED_MODE_UP[0] if (port_idx < 49) else self.LED_MODE_UP[1]
else:
return self.LED_MODE_DOWN[0] if (port_idx < 49) else self.LED_MODE_DOWN[1]
def _port_led_mode_update(self, port_idx, ledMode):
with open(self.f_led.format("port{}".format(port_idx)), 'w') as led_file:
led_file.write(str(ledMode))
def _initSystemLed(self):
try:
with open(self.f_led.format("system"), 'w') as led_file:
led_file.write("1")
DBG_PRINT("init system led to normal")
with open(self.f_led.format("idn"), 'w') as led_file:
led_file.write("1")
DBG_PRINT("init idn led to off")
except IOError as e:
DBG_PRINT(str(e))
def _initPanelLed(self):
with open(self.f_led.format("port1"), 'r') as led_file:
shouldInit = (int(led_file.read()) == 0)
if shouldInit == True:
for idx in range(1, 53):
defmode = self._port_state_to_mode(idx, "down")
with open(self.f_led.format("port{}".format(idx)), 'w') as led_file:
led_file.write(str(defmode))
DBG_PRINT("init port{} led to mode={}".format(idx, defmode))
def _initDefaultConfig(self):
DBG_PRINT("start init led")
self._initSystemLed()
self._initPanelLed()
DBG_PRINT("init led done")
# Concrete implementation of port_link_state_change() method
def port_link_state_change(self, portname, state):
port_idx = self._port_name_to_index(portname)
ledMode = self._port_state_to_mode(port_idx, state)
with open(self.f_led.format("port{}".format(port_idx)), 'r') as led_file:
saveMode = int(led_file.read())
if ledMode == saveMode:
return
self._port_led_mode_update(port_idx, ledMode)
DBG_PRINT("update {} led mode from {} to {}".format(portname, saveMode, ledMode))
# Constructor
def __init__(self):
self.SONIC_PORT_NAME_PREFIX = "Ethernet"
self.LED_MODE_UP = [2, 11]
self.LED_MODE_DOWN = [1, 7]
self.f_led = "/sys/class/leds/{}/brightness"
self._initDefaultConfig()

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python
#############################################################################
# Centec
#
# Module contains an implementation of SONiC PSU Base API and
# provides the PSUs status which are available in the platform
#
#############################################################################
try:
from sonic_psu.psu_base import PsuBase
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class PsuUtil(PsuBase):
"""Platform-specific PSUutil class"""
def __init__(self):
PsuBase.__init__(self)
self.psu_path = "/sys/class/psu/psu{}/"
self.psu_presence = "psu_presence"
self.psu_oper_status = "psu_status"
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
return 2
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined
by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is faulty
"""
if index is None:
return False
status = 0
try:
with open(self.psu_path.format(index) + self.psu_oper_status, 'r') as power_status:
status = int(power_status.read())
except IOError:
return False
return status == 1
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by 1-based index <index>
:param index: An integer, 1-based index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
if index is None:
return False
status = 0
try:
with open(self.psu_path.format(index) + self.psu_presence, 'r') as presence_status:
status = int(presence_status.read())
except IOError:
return False
return status == 1

View File

@ -0,0 +1,138 @@
#!/usr/bin/env python
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
try:
import time
from socket import *
from select import *
from sonic_sfp.sfputilbase import SfpUtilBase
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
def DBG_PRINT(str):
print str + "\n"
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def sfp_base(self):
return self.SFP_BASE
@property
def qsfp_ports(self):
return ()
@property
def port_to_eeprom_mapping(self):
return self.eeprom_mapping
def is_logical_port(self, port_name):
return True
def get_logical_to_physical(self, port_name):
if not port_name.startswith(self.SONIC_PORT_NAME_PREFIX):
return None
port_idx = int(port_name[len(self.SONIC_PORT_NAME_PREFIX):])
return [port_idx]
def get_eeprom_data(self, port):
ret = None
port_num = self.get_logical_to_physical(port)[0]
if port_num < self.port_start or port_num > self.port_end:
return ret
if port_num < self.sfp_base:
return ret
try:
with open(self.eeprom_mapping[port_num], 'r') as eeprom_file:
ret = eeprom_file.read()
except IOError as e:
DBG_PRINT(str(e))
return ret
# todo
#def _get_port_eeprom_path(self, port_num, devid):
# pass
def __init__(self):
self.SONIC_PORT_NAME_PREFIX = "Ethernet"
self.PORT_START = 1
self.PORT_END = 52
self.SFP_BASE = 49
self.PORTS_IN_BLOCK = 52
self.eeprom_mapping = {}
self.f_sfp_present = "/sys/class/sfp/sfp{}/sfp_presence"
self.f_sfp_enable = "/sys/class/sfp/sfp{}/sfp_enable"
for x in range(self.port_start, self.sfp_base):
self.eeprom_mapping[x] = None
for x in range(self.sfp_base, self.port_end + 1):
self.eeprom_mapping[x] = "/sys/class/sfp/sfp{}/sfp_eeprom".format(x - self.sfp_base + 1)
self.presence = {}
for x in range(self.sfp_base, self.port_end + 1):
self.presence[x] = False;
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
if port_num < self.sfp_base:
return False
try:
with open(self.f_sfp_present.format(port_num - self.sfp_base + 1), 'r') as sfp_file:
return 1 == int(sfp_file.read())
except IOError as e:
DBG_PRINT(str(e))
return False
def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def reset(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
return False
def get_transceiver_change_event(self, timeout=0):
port_dict = {}
while True:
for x in range(self.sfp_base, self.port_end + 1):
presence = self.get_presence(x)
if presence != self.presence[x]:
self.presence[x] = presence
port_dict[x] = presence
return True, port_dict
time.sleep(0.5)

View File

@ -0,0 +1,7 @@
# docker image for docker-ptf-centec
DOCKER_PTF_CENTEC = docker-ptf-centec.gz
$(DOCKER_PTF_CENTEC)_PATH = $(DOCKERS_PATH)/docker-ptf-saithrift
$(DOCKER_PTF_CENTEC)_DEPENDS += $(PYTHON_SAITHRIFT)
$(DOCKER_PTF_CENTEC)_LOAD_DOCKERS += $(DOCKER_PTF)
SONIC_DOCKER_IMAGES += $(DOCKER_PTF_CENTEC)

View File

@ -0,0 +1,15 @@
# docker image for centec saiserver
DOCKER_SAISERVER_CENTEC = docker-saiserver-centec.gz
$(DOCKER_SAISERVER_CENTEC)_PATH = $(PLATFORM_PATH)/docker-saiserver-centec
$(DOCKER_SAISERVER_CENTEC)_DEPENDS += $(SAISERVER)
$(DOCKER_SAISERVER_CENTEC)_FILES += $(DSSERVE) $(BCMCMD)
$(DOCKER_SAISERVER_CENTEC)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_STRETCH)
SONIC_DOCKER_IMAGES += $(DOCKER_SAISERVER_CENTEC)
$(DOCKER_SAISERVER_CENTEC)_CONTAINER_NAME = saiserver
$(DOCKER_SAISERVER_CENTEC)_RUN_OPT += --privileged -t
$(DOCKER_SAISERVER_CENTEC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SAISERVER_CENTEC)_RUN_OPT += -v /var/run/docker-saiserver:/var/run/sswsyncd
$(DOCKER_SAISERVER_CENTEC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
$(DOCKER_SAISERVER_CENTEC)_RUN_OPT += -v /host/warmboot:/var/warmboot

View File

@ -0,0 +1,24 @@
# docker image for centec syncd with rpc
DOCKER_SYNCD_CENTEC_RPC = docker-syncd-centec-rpc.gz
$(DOCKER_SYNCD_CENTEC_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-centec-rpc
$(DOCKER_SYNCD_CENTEC_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT)
$(DOCKER_SYNCD_CENTEC_RPC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)
ifeq ($(INSTALL_DEBUG_TOOLS), y)
$(DOCKER_SYNCD_CENTEC_RPC)_DEPENDS += $(SYNCD_RPC_DBG) \
$(LIBSWSSCOMMON_DBG) \
$(LIBSAIMETADATA_DBG) \
$(LIBSAIREDIS_DBG)
endif
$(DOCKER_SYNCD_CENTEC_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_BASE)
SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_CENTEC_RPC)
SONIC_STRETCH_DOCKERS += $(DOCKER_SYNCD_CENTEC_RPC)
ifeq ($(ENABLE_SYNCD_RPC),y)
SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_CENTEC_RPC)
endif
$(DOCKER_SYNCD_CENTEC_RPC)_CONTAINER_NAME = syncd
$(DOCKER_SYNCD_CENTEC_RPC)_RUN_OPT += --privileged -t
$(DOCKER_SYNCD_CENTEC_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SYNCD_CENTEC_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro
$(DOCKER_SYNCD_CENTEC_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot

View File

@ -0,0 +1,51 @@
FROM docker-syncd-centec
## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive
COPY \
{% for deb in docker_syncd_centec_rpc_debs.split(' ') -%}
debs/{{ deb }}{{' '}}
{%- endfor -%}
debs/
RUN apt-get purge -y syncd
RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } ; \
{% for deb in docker_syncd_centec_rpc_debs.split(' ') -%}
dpkg_apt debs/{{ deb }}{{'; '}}
{%- endfor %}
## Pre-install the fundamental packages
RUN apt-get update \
&& apt-get -y install \
net-tools \
python-pip \
build-essential \
libssl-dev \
libffi-dev \
python-dev \
wget \
cmake \
&& wget https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz \
&& tar xvfz 1.0.0.tar.gz \
&& cd nanomsg-1.0.0 \
&& mkdir -p build \
&& cmake . \
&& make install \
&& ldconfig \
&& cd .. \
&& rm -fr nanomsg-1.0.0 \
&& rm -f 1.0.0.tar.gz \
&& pip install cffi==1.7.0 \
&& pip install --upgrade cffi==1.7.0 \
&& pip install nnpy \
&& mkdir -p /opt \
&& cd /opt \
&& wget https://raw.githubusercontent.com/p4lang/ptf/master/ptf_nn/ptf_nn_agent.py \
&& apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y \
&& rm -rf /root/deps
COPY ["ptf_nn_agent.conf", "/etc/supervisor/conf.d/"]
ENTRYPOINT ["/usr/bin/supervisord"]

View File

@ -0,0 +1,10 @@
[program:ptf_nn_agent]
command=/usr/bin/python /opt/ptf_nn_agent.py --device-socket 1@tcp://0.0.0.0:10900 -i 1-3@Ethernet12 --set-iface-rcv-buffer=109430400
process_name=ptf_nn_agent
stdout_logfile=/tmp/ptf_nn_agent.out.log
stderr_logfile=/tmp/ptf_nn_agent.err.log
redirect_stderr=false
autostart=true
autorestart=true
startsecs=1
numprocs=1

View File

@ -0,0 +1,17 @@
# docker image for centec syncd
DOCKER_SYNCD_PLATFORM_CODE = centec
include $(PLATFORM_PATH)/../template/docker-syncd-base.mk
$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(PYTHON_SDK_API)
$(DOCKER_SYNCD_CENTEC)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)
$(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \
$(LIBSWSSCOMMON_DBG) \
$(LIBSAIMETADATA_DBG) \
$(LIBSAIREDIS_DBG)
$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot
$(DOCKER_SYNCD_CENTEC)_RUN_OPT += --privileged -t
$(DOCKER_SYNCD_CENTEC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf
$(DOCKER_SYNCD_CENTEC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd
$(DOCKER_SYNCD_CENTEC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro

View File

@ -0,0 +1,37 @@
FROM docker-config-engine-stretch
ARG docker_container_name
RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf
## Make apt-get non-interactive
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update
COPY \
{% for deb in docker_syncd_centec_debs.split(' ') -%}
debs/{{ deb }}{{' '}}
{%- endfor -%}
debs/
RUN apt-get update \
&& apt-get -y install \
net-tools \
iputils-ping
RUN apt-get -y install libpcap-dev libxml2-dev python-dev swig libsensors4-dev libjemalloc1 nfs-common
RUN dpkg -i \
{% for deb in docker_syncd_centec_debs.split(' ') -%}
debs/{{ deb }}{{' '}}
{%- endfor %}
COPY ["supervisord.conf", "/etc/supervisor/conf.d/"]
COPY ["files/supervisor-proc-exit-listener", "/usr/bin/"]
COPY ["critical_processes", "/etc/supervisor/"]
## Clean up
RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y
RUN rm -rf /debs
ENTRYPOINT ["/usr/bin/supervisord"]

View File

@ -0,0 +1 @@
syncd

View File

@ -0,0 +1,37 @@
[supervisord]
logfile_maxbytes=1MB
logfile_backups=2
nodaemon=true
[eventlistener:dependent-startup]
command=python -m supervisord_dependent_startup
autostart=true
autorestart=unexpected
startretries=0
exitcodes=0,3
events=PROCESS_STATE
[eventlistener:supervisor-proc-exit-listener]
command=/usr/bin/supervisor-proc-exit-listener --container-name syncd
events=PROCESS_STATE_EXITED
autostart=true
autorestart=unexpected
[program:rsyslogd]
command=/usr/sbin/rsyslogd -n -iNONE
priority=1
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
dependent_startup=true
[program:syncd]
command=/usr/bin/syncd_start.sh
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
dependent_startup=true
dependent_startup_wait_for=rsyslogd:running

View File

@ -0,0 +1,12 @@
#!/usr/bin/env bash
function clean_up {
service syncd stop
exit
}
trap clean_up SIGTERM SIGKILL
service syncd start
read

View File

@ -0,0 +1,20 @@
# libsaithrift-dev package
SAI_VER = 0.9.4
LIBSAITHRIFT_DEV = libsaithrift-dev_$(SAI_VER)_$(CONFIGURED_ARCH).deb
$(LIBSAITHRIFT_DEV)_SRC_PATH = $(SRC_PATH)/sonic-sairedis/SAI
$(LIBSAITHRIFT_DEV)_DEPENDS += $(LIBTHRIFT) $(LIBTHRIFT_DEV) $(PYTHON_THRIFT) $(THRIFT_COMPILER) $(CENTEC_SAI)
$(LIBSAITHRIFT_DEV)_RDEPENDS += $(LIBTHRIFT) $(CENTEC_SAI)
SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV)
PYTHON_SAITHRIFT = python-saithrift_$(SAI_VER)_$(CONFIGURED_ARCH).deb
$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(PYTHON_SAITHRIFT)))
SAISERVER = saiserver_$(SAI_VER)_$(CONFIGURED_ARCH).deb
$(SAISERVER)_RDEPENDS += $(LIBTHRIFT) $(CENTEC_SAI)
$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(SAISERVER)))
SAISERVER_DBG = saiserver-dbg_$(SAI_VER)_$(CONFIGURED_ARCH).deb
$(SAISERVER_DBG)_RDEPENDS += $(SAISERVER)
$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(SAISERVER_DBG)))

View File

@ -0,0 +1,22 @@
pinctrl-ctc
mtdblock
ofpart
spi-ctc-qspi
spi-nor
m25p80
i2c-ctc
i2c-dev
rtc-sd2405
ctc5236_switch
ctc5236_mdio
ctcmac
ctcmac_test
ctc5236-mc
ctc_wdt
ehci-ctc
sdhci-ctc5236
gpio-ctc
pwm-ctc
ext4
overlay
squashfs

View File

@ -0,0 +1,18 @@
# sonic centec one image installer
SONIC_ONE_IMAGE = sonic-centec-arm64.bin
$(SONIC_ONE_IMAGE)_MACHINE = centec-arm64
$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie
$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_INSTALLS += $(TSINGMA_BSP_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_48T4X_P_PLATFORM_MODULE)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(CENTEC_E530_24X2C_PLATFORM_MODULE)
ifeq ($(INSTALL_DEBUG_TOOLS),y)
$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES)
$(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES))
else
$(SONIC_ONE_IMAGE)_DOCKERS = $(SONIC_INSTALL_DOCKER_IMAGES)
endif
SONIC_INSTALLERS += $(SONIC_ONE_IMAGE)

View File

@ -0,0 +1,18 @@
# Centec E530-48T4X-P Platform modules
CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION =1.1
CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION =1.1
export CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION
CENTEC_E530_48T4X_P_PLATFORM_MODULE = platform-modules-e530-48t4x-p_$(CENTEC_E530_48T4X_P_PLATFORM_MODULE_VERSION)_arm64.deb
$(CENTEC_E530_48T4X_P_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-e530
$(CENTEC_E530_48T4X_P_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_48t4x_p-r0
$(CENTEC_E530_48T4X_P_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
SONIC_DPKG_DEBS += $(CENTEC_E530_48T4X_P_PLATFORM_MODULE)
CENTEC_E530_24X2C_PLATFORM_MODULE = platform-modules-e530-24x2c_$(CENTEC_E530_24X2C_PLATFORM_MODULE_VERSION)_arm64.deb
$(CENTEC_E530_24X2C_PLATFORM_MODULE)_PLATFORM = arm64-centec_e530_24x2c-r0
$(eval $(call add_extra_package,$(CENTEC_E530_48T4X_P_PLATFORM_MODULE),$(CENTEC_E530_24X2C_PLATFORM_MODULE)))

View File

@ -0,0 +1,46 @@
# Copyright (C) Centec Inc
# over ride default behaviour
echo "Preparing for installation ... "
demo_mnt=/mnt
hw_load() {
echo "ext4load mmc 0:2 \$loadaddr onie_uimage"
}
create_partition() {
echo y | mkfs.ext4 -L CTC-SYSTEM /dev/mmcblk0p1
}
mount_partition() {
echo "mount flash"
mount -t ext4 /dev/mmcblk0p1 $demo_mnt
}
bootloader_menu_config() {
mkdir -p $demo_mnt/boot
mount -t ext4 /dev/mmcblk0p2 $demo_mnt/boot
rm $demo_mnt/boot/centec-e530.itb -rf
cp $demo_mnt/$image_dir/boot/sonic_arm64.fit $demo_mnt/boot/centec-e530.itb
cd $demo_mnt/boot
rm onie_uimage -rf
ln -s centec-e530.itb onie_uimage
cd -
sync
umount -l $demo_mnt/boot
hw_load_str="$(hw_load)"
(cat <<EOF
hw_load $hw_load_str
copy_img echo "Loading Demo $platform image..." && run hw_load
nos_bootcmd run copy_img && setenv bootargs quiet console=\$consoledev,\$baudrate root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 loopfstype=squashfs loop=$image_dir/fs.squashfs && bootm \$loadaddr
EOF
) > /tmp/env.txt
fw_setenv -f -s /tmp/env.txt
fw_setenv -f image_dir $image_dir
}

18
platform/centec-arm64/rules.mk Executable file
View File

@ -0,0 +1,18 @@
include $(PLATFORM_PATH)/sai.mk
include $(PLATFORM_PATH)/docker-syncd-centec.mk
include $(PLATFORM_PATH)/docker-syncd-centec-rpc.mk
include $(PLATFORM_PATH)/one-image.mk
include $(PLATFORM_PATH)/libsaithrift-dev.mk
include $(PLATFORM_PATH)/docker-ptf-centec.mk
include $(PLATFORM_PATH)/tsingma-bsp.mk
include $(PLATFORM_PATH)/platform-modules-centec-e530.mk
SONIC_ALL += $(SONIC_ONE_IMAGE) \
$(DOCKER_FPM)
# $(DOCKER_SYNCD_CENTEC_RPC)
# Inject centec sai into sairedis
$(LIBSAIREDIS)_DEPENDS += $(CENTEC_SAI) $(LIBSAITHRIFT_DEV_CENTEC)
# Runtime dependency on centec sai is set only for syncd
$(SYNCD)_RDEPENDS += $(CENTEC_SAI)

8
platform/centec-arm64/sai.mk Executable file
View File

@ -0,0 +1,8 @@
# Centec SAI
export CENTEC_SAI_VERSION = 1.6.3-1
export CENTEC_SAI = libsai_$(CENTEC_SAI_VERSION)_$(PLATFORM_ARCH).deb
$(CENTEC_SAI)_URL = https://github.com/CentecNetworks/sonic-binaries/raw/master/$(PLATFORM_ARCH)/sai/$(CENTEC_SAI)
SONIC_ONLINE_DEBS += $(CENTEC_SAI)

View File

@ -0,0 +1 @@
obj-m := centec_e530_24x2c_platform.o

View File

@ -0,0 +1,13 @@
[Unit]
Description=Centec modules init
After=local-fs.target
Before=syncd.service
[Service]
Type=oneshot
ExecStart=-/etc/init.d/platform-modules-e530-24x2c start
ExecStop=-/etc/init.d/platform-modules-e530-24x2c stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
from setuptools import setup
os.listdir
setup(
name='24x2c',
version='1.1',
description='Module to initialize centec e530-24x2c platforms',
packages=['24x2c'],
package_dir={'24x2c': '24x2c/classes'},
)

View File

@ -0,0 +1 @@
obj-m := centec_e530_48t4x_p_platform.o

View File

@ -0,0 +1,13 @@
[Unit]
Description=Centec modules init
After=local-fs.target
Before=syncd.service
[Service]
Type=oneshot
ExecStart=-/etc/init.d/platform-modules-e530-48t4x-p start
ExecStop=-/etc/init.d/platform-modules-e530-48t4x-p stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,15 @@
#!/usr/bin/env python
import os
from setuptools import setup
os.listdir
setup(
name='48t4x_p',
version='1.1',
description='Module to initialize centec e530-48t4x-p platforms',
packages=['48t4x_p'],
package_dir={'48t4x_p': '48t4x_p/classes'},
)

View File

@ -0,0 +1,15 @@
Copyright (C) 2019 Centec, Inc
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.

View File

@ -0,0 +1 @@
platform drivers for Centec E530 for the SONiC project

View File

@ -0,0 +1,11 @@
sonic-centec-platform-modules (1.1) unstable; urgency=low
* Add support for centec e530-48t4x-p and e530-24x2c
-- shil <shil@centecnetworks.com> Fri, 15 Nov 2019 13:36:54 +0800
sonic-centec-platform-modules (1.0) unstable; urgency=low
* Initial release
-- shil <shil@centecnetworks.com> Fri, 15 Nov 2019 13:35:06 +0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,16 @@
Source: sonic-centec-platform-modules
Section: main
Priority: extra
Maintainer: shil <shil@centecnetworks.com>
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
Package: platform-modules-e530-48t4x-p
Architecture: arm64
Depends: linux-image-4.19.0-9-2-arm64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-e530-24x2c
Architecture: arm64
Depends: linux-image-4.19.0-9-2-arm64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp

View File

@ -0,0 +1,61 @@
#!/bin/bash
# This script load/unload centec kernel modules
### BEGIN INIT INFO
# Provides: platform-modules-e530-24x2c
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Load Centec kernel modules
### END INIT INFO
function load_kernel_modules()
{
depmod -a
modprobe centec_e530_24x2c_platform
modprobe dal
modprobe tun
modprobe tap
}
function remove_kernel_modules()
{
modprobe -r tap
modprobe -r tun
modprobe -r dal
modprobe -r centec_e530_24x2c_platform
}
case "$1" in
start)
echo -n "Load Centec kernel modules... "
load_kernel_modules
echo "done."
;;
stop)
echo -n "Unload Centec kernel modules... "
remove_kernel_modules
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-e530-24x2c {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,3 @@
../../centec/centec-dal/dal.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
24x2c/modules/centec_e530_24x2c_platform.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
24x2c/service/24x2c_platform.service /lib/systemd/system

View File

@ -0,0 +1,2 @@
systemctl enable 24x2c_platform.service
systemctl start 24x2c_platform.service

View File

@ -0,0 +1,61 @@
#!/bin/bash
# This script load/unload centec kernel modules
### BEGIN INIT INFO
# Provides: platform-modules-e530-48t4x-p
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Load Centec kernel modules
### END INIT INFO
function load_kernel_modules()
{
depmod -a
modprobe centec_e530_48t4x_p_platform
modprobe dal
modprobe tun
modprobe tap
}
function remove_kernel_modules()
{
modprobe -r tap
modprobe -r tun
modprobe -r dal
modprobe -r centec_e530_48t4x_p_platform
}
case "$1" in
start)
echo -n "Load Centec kernel modules... "
load_kernel_modules
echo "done."
;;
stop)
echo -n "Unload Centec kernel modules... "
remove_kernel_modules
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-e530-48t4x-p {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,3 @@
../../centec/centec-dal/dal.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
48t4x_p/modules/centec_e530_48t4x_p_platform.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
48t4x_p/service/48t4x_p_platform.service /lib/systemd/system

View File

@ -0,0 +1,2 @@
systemctl enable 48t4x_p_platform.service
systemctl start 48t4x_p_platform.service

View File

@ -0,0 +1,91 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
include /usr/share/dpkg/pkg-info.mk
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
export INSTALL_MOD_DIR:=extra
PYTHON ?= python2
PACKAGE_PRE_NAME := sonic-platform-modules-e530
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= 48t4x_p 24x2c
MODULE_DIR := modules
UTILS_DIR := utils
SERVICE_DIR := service
CLASSES_DIR := classes
CONF_DIR := conf
KDAL_DIR := ../../centec/centec-dal/
%:
dh $@ --with systemd,python2,python3 --buildsystem=pybuild
clean:
dh_testdir
dh_testroot
dh_clean
build:
#make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC)
(for mod in $(KDAL_DIR); do \
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/; \
done)
(for mod in $(MODULE_DIRS); do \
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
$(PYTHON) $${mod}/setup.py build; \
done)
binary: binary-arch binary-indep
# Nothing to do
binary-arch:
# Nothing to do
#install: build
#dh_testdir
#dh_testroot
#dh_clean -k
#dh_installdirs
binary-indep:
dh_testdir
dh_installdirs
# Custom package commands
(for mod in $(MODULE_DIRS); do \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/local/bin; \
dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system; \
cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
cp $(MOD_SRC_DIR)/$(KDAL_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
$(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \
done)
# Resuming debhelper scripts
dh_testroot
dh_install
dh_installchangelogs
dh_installdocs
dh_systemd_enable
dh_installinit
dh_systemd_start
dh_link
dh_fixperms
dh_compress
dh_strip
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
.PHONY: build binary binary-arch binary-indep clean

View File

@ -0,0 +1,62 @@
/*
*Copyright 2018 CENTEC
*
*/
/dts-v1/;
/ {
description = "arm64 kernel, initramfs and FDT blob";
#address-cells = <1>;
images {
kernel_ctc {
description = "ARM64 Kernel";
data = /incbin/("./vmlinuz-4.19.0-9-2-arm64");
type = "kernel";
arch = "arm64";
os = "linux";
compression = "none";
load = <0x80080000>;
entry = <0x80080000>;
hash {
algo = "crc32";
};
};
initramfs {
description = "initramfs";
data = /incbin/("./initrd.img-4.19.0-9-2-arm64");
type = "ramdisk";
arch = "arm64";
os = "linux";
compression = "gzip";
load = <0x85000000>;
entry = <0x85000000>;
hash {
algo = "crc32";
};
};
ctc_fdt {
description = "dtb for tm_ctc5236";
data = /incbin/("./e530-ctc5236.dtb");
type = "flat_dt";
arch = "arm64";
os = "linux";
compression = "none";
load = <0x88000000>;
hash {
algo = "crc32";
};
};
};
configurations {
default = "e530-ctc5236";
e530-ctc5236 {
description = "config for tm_ctc5236";
kernel = "kernel_ctc";
ramdisk = "initramfs";
fdt = "ctc_fdt";
};
};
};

View File

@ -0,0 +1,12 @@
# Centec TsingMa BSP Platform modules
TSINGMA_BSP_MODULE_VERSION = 1.0
export TSINGMA_BSP_MODULE_VERSION
TSINGMA_BSP_MODULE = tsingma-bsp_$(TSINGMA_BSP_MODULE_VERSION)_$(PLATFORM_ARCH).deb
$(TSINGMA_BSP_MODULE)_SRC_PATH = $(PLATFORM_PATH)/tsingma-bsp
$(TSINGMA_BSP_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON)
SONIC_DPKG_DEBS += $(TSINGMA_BSP_MODULE)

View File

@ -0,0 +1,15 @@
Copyright (C) 2019 Centec, Inc
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.

View File

@ -0,0 +1 @@
platform drivers for Centec TsingMa soc

View File

@ -0,0 +1,5 @@
tsingma-bsp (1.0) unstable; urgency=low
* Initial release
-- shil <shil@centecnetworks.com> Wed, 24 Jun 2020 14:20:58 +0800

View File

@ -0,0 +1 @@
9

View File

@ -0,0 +1,11 @@
Source: tsingma-bsp
Section: main
Priority: extra
Maintainer: shil <shil@centecnetworks.com>
Build-Depends: debhelper (>= 8.0.0), bzip2
Standards-Version: 3.9.3
Package: tsingma-bsp
Architecture: arm64
Depends: linux-image-4.19.0-9-2-arm64-unsigned
Description: kernel modules for tsingma bsp

View File

@ -0,0 +1,66 @@
#!/usr/bin/make -f
# -*- makefile -*-
# Sample debian/rules that uses debhelper.
# This file was originally written by Joey Hess and Craig Small.
# As a special exception, when this file is copied by dh-make into a
# dh-make output file, you may use that output file without restriction.
# This special exception was added by Craig Small in version 0.37 of dh-make.
include /usr/share/dpkg/pkg-info.mk
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
PACKAGE_PRE_NAME := tsingma-bsp
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= ctc5236-mc ctc5236_switch ctcmac ctc_wdt ehci-ctc gpio-ctc i2c-ctc pinctrl-ctc pwm-ctc rtc-sd2405 sdhci-ctc5236 spi-ctc-qspi
DTS_DIR := ctc-dts
MODULE_DIR := src
UTILS_DIR := utils
SERVICE_DIR := service
CLASSES_DIR := classes
CONF_DIR := conf
%:
dh $@ --with systemd,python2,python3 --buildsystem=pybuild
clean:
dh_testdir
dh_testroot
dh_clean
build:
(for mod in $(MODULE_DIRS); do \
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$(MODULE_DIR)/$${mod}; \
done)
make -C $(MOD_SRC_DIR)/$(MODULE_DIR)/$(DTS_DIR)
binary: binary-arch binary-indep
# Nothing to do
binary-arch:
# Nothing to do
binary-indep:
dh_testdir
dh_installdirs
# Resuming debhelper scripts
dh_testroot
dh_install
dh_installchangelogs
dh_installdocs
dh_systemd_enable
dh_installinit
dh_systemd_start
dh_link
dh_fixperms
dh_compress
dh_strip
dh_installdeb
dh_gencontrol
dh_md5sums
dh_builddeb
.PHONY: build binary binary-arch binary-indep clean

View File

@ -0,0 +1,49 @@
#!/bin/bash
# This script config centec tsingma soc
### BEGIN INIT INFO
# Provides: tsingma-bsp
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Config Centec TsingMa SOC
### END INIT INFO
function config_tsingma_soc()
{
hwaddr=`fw_printenv ethaddr | awk -F = '{print $2}'`
if [ "$hwaddr" != "" ]; then
ifconfig eth0 hw ether $hwaddr
fi
modprobe tun
modprobe tap
}
case "$1" in
start)
echo -n "Config Centec TsingMa SOC... "
config_tsingma_soc
echo "done."
;;
stop)
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/tsingma-bsp {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,17 @@
src/ctc5236-mc/ctc5236-mc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/pwm-ctc/pwm-ctc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctc5236_switch/ctc5236_switch.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/pinctrl-ctc/pinctrl-ctc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctc_wdt/ctc_wdt.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctcmac/ctcmac.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctcmac/ctcmac_test.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctcmac/ctc5236_mdio.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/i2c-ctc/i2c-ctc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/gpio-ctc/gpio-ctc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ehci-ctc/ehci-ctc.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/rtc-sd2405/rtc-sd2405.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/sdhci-ctc5236/sdhci-ctc5236.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/spi-ctc-qspi/spi-ctc-qspi.ko /lib/modules/4.19.0-9-2-arm64/kernel/extra
src/ctc-dts/e530-ctc5236.dtb /boot/
src/config/fw_env.config /etc/
src/config/tsingma-bsp.service /lib/systemd/system

View File

@ -0,0 +1,2 @@
systemctl enable tsingma-bsp.service
systemctl start tsingma-bsp.service

View File

@ -0,0 +1,2 @@
# MTD device name Device offset Env. size Flash sector size
/dev/mtd1 0x00000000 0x00010000 0x00001000

View File

@ -0,0 +1,13 @@
[Unit]
Description=Centec tsingma bsp init
After=local-fs.target
Before=syncd.service
[Service]
Type=oneshot
ExecStart=-/etc/init.d/tsingma-bsp start
ExecStop=-/etc/init.d/tsingma-bsp stop
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,4 @@
e530-ctc5236.dtb: e530-ctc5236.dts ctc5236.dtsi ctc5236-clock.dtsi
cpp -nostdinc -I. -undef -x assembler-with-cpp e530-ctc5236.dts > tmp.dts
dtc -O dtb -o e530-ctc5236.dtb tmp.dts
rm tmp.dts -rf

View File

@ -0,0 +1,22 @@
/*
* This header provides constants for the ARM GIC.
*/
#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
#define _DT_BINDINGS_INTERRUPT_CONTROLLER_ARM_GIC_H
#include "irq.h"
/* interrupt specifier cell 0 */
#define GIC_SPI 0
#define GIC_PPI 1
/*
* Interrupt specifier cell 2.
* The flags in irq.h are valid, plus those below.
*/
#define GIC_CPU_MASK_RAW(x) ((x) << 8)
#define GIC_CPU_MASK_SIMPLE(num) GIC_CPU_MASK_RAW((1 << (num)) - 1)
#endif

View File

@ -0,0 +1,25 @@
/*
* ctc5236 clock tree IDs
*
* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
*
* Jay Cao <caoj@centecnetworks.com>
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __CTC5236_CLKS_H
#define __CTC5236_CLKs_H
#define CLKID_UNUSED 0
#define CLKID_PLL_FIXED 1
#define CLKID_UART0 2
#endif /* __CTC5236_CLKS_H */

View File

@ -0,0 +1,63 @@
/*
* dts file for Centec CTC5236(TsingMa) SoC
*
* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
*
* Jay Cao <caoj@centecnetworks.com>
*
* 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.
*/
osc: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
};
sup_clk: sup_clk_12m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <1200000000>;
clock-output-names = "sup_clk";
};
uart_clk: uart_clk_20m {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <20000000>;
clock-output-names = "uart_clk";
};
i2c_clk: clkm {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <50000000>;
clock-output-names = "i2c_clk";
};
wdog_clk:wdog_clk{
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <1000000>;
clock-output-names = "wdog_clk";
};
timer_clk:timer_clk{
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <500000000>;
clock-output-names = "timer_clk";
};
mmc_clk:mmc_clk{
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <100000000>;
clock-output-names = "mmc_clk";
};
spi_clk:spi_clk{
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <100000000>;
clock-output-names = "spi_clk";
};

View File

@ -0,0 +1,376 @@
/*
* dts file for Centec CTC5236(TsingMa) SoC
*
* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
*
* Jay Cao <caoj@centecnetworks.com>
*
* 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.
*/
#include "arm-gic.h"
#include "ctc5236-clks.h"
#include "../pinctrl-ctc/pinctrl-ctc.h"
/ {
compatible = "centec,ctc5236";
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&gic>;
cpus {
#address-cells = <2>;
#size-cells = <0>;
cpu-map {
cluster0 {
core0 {
cpu = <&cpu0>;
};
core1 {
cpu = <&cpu1>;
};
};
};
cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0 0x000>;
enable-method = "spin-table";
cpu-release-addr = <0 0x0010fff0>;
};
cpu1: cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a53", "arm,armv8";
reg = <0 0x001>;
enable-method = "spin-table";
cpu-release-addr = <0 0x0010fff0>;
};
};
gic: interrupt-controller@31201000 {
compatible = "arm,gic-400";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x0 0x31201000 0 0x1000>,
<0x0 0x31202000 0 0x2000>,
<0x0 0x31204000 0 0x2000>,
<0x0 0x31206000 0 0x2000>;
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
};
timer {
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
};
soc: soc {
compatible = "simple-bus";
#address-cells = <2>;
#size-cells = <2>;
ranges;
#include "ctc5236-clock.dtsi"
ocram: sram@00100000 {
compatible = "mmio-sram";
reg = <0x0 0x00100000 0x0 0x10000>;
};
memory-controller@30600000 {
compatible = "ctc,ctc5236-ddr-ctrl";
reg = <0x0 0x30600000 0x0 0x100000>;
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
};
sysctrl: sysctrl@33200000 {
compatible = "ctc,ctc5236-sysctrl", "syscon";
reg = <0x0 0x33200000 0x0 0x100000>;
little-endian;
};
serial0: serial@33000000 {
compatible = "arm,pl011","arm,primecell";
reg = <0x0 0x33000000 0x0 0x1000>;
interrupts = <GIC_SPI 25 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&uart_clk>, <&sup_clk>;
clock-names = "uart_clk", "apb_pclk";
status="disabled";
};
serial1: serial@33001000 {
compatible = "arm,pl011","arm,primecell";
reg = <0x0 0x33001000 0x0 0x1000>;
interrupts = <GIC_SPI 26 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&uart_clk>, <&sup_clk>;
clock-names = "uart_clk", "apb_pclk";
status="disabled";
};
serial2: serial@33002000 {
compatible = "arm,pl011","arm,primecell";
reg = <0x0 0x33002000 0x0 0x1000>;
interrupts = <GIC_SPI 27 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
clocks = <&uart_clk>, <&sup_clk>;
clock-names = "uart_clk", "apb_pclk";
status="disabled";
};
mdio: mdio@33620000 {
compatible = "ctc,mdio";
reg = <0x0 0x33620000 0x0 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
};
enet0: ethernet@33410000 {
compatible = "ctc,mac";
device_type = "network";
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&gic>;
status = "disabled";
index = <0x00>;
reg = <0x0 0x33410000 0x0 0x10000>,
<0x0 0x33400000 0x0 0x10000>;
interrupts = <GIC_SPI 40 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 41 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
ctc,sysctrl = <&sysctrl>;
};
enet1: ethernet@33420000 {
compatible = "ctc,mac";
device_type = "network";
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&gic>;
status = "disabled";
index = <0x01>;
reg = <0x0 0x33420000 0x0 0x10000>,
<0x0 0x33400000 0x0 0x10000>;
interrupts = <GIC_SPI 42 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 43 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
ctc,sysctrl = <&sysctrl>;
};
ehci0: usb@30500000 {
compatible = "ctc-ehci";
reg = <0x0 0x30500000 0x0 0x1000>;
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
ohci0: usb@30580000 {
compatible = "generic-ohci";
reg = <0x0 0x30580000 0x0 0x1000>;
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
spi: spi@33100000 {
compatible = "arm,pl022","arm,primecell";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x33100000 0x0 0x100000>;
clocks = <&spi_clk>, <&sup_clk>;
clock-names = "spi_clk", "apb_pclk";
num-cs = <4>;
interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
ctc,sysctrl = <&sysctrl>;
status ="disabled";
};
qspi: qspi@10000000 {
compatible = "ctc, igdaxi001a-qspi";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x10000000 0x0 0x10000>;
pclk = <500000000>;
num-cs = <2>;
idle-cycle = <2>;
post-cycle = <1>;
pre-cycle = <2>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
switch: switch@31100000 {
compatible = "centec,dal-localbus";
reg = <0x0 0x31100000 0x0 0x1000>,
<0x0 0x33290000 0x0 0x10000>;
interrupts = <GIC_SPI 128 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 129 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 130 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 131 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 132 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 133 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 134 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_SPI 135 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
status ="disabled";
};
switch1: switch1@31101000 {
compatible = "centec,switch";
reg = <0x0 0x31101000 0x0 0x1000>;
status ="disabled";
};
i2c0: i2c0@33700000{
compatible = "ctc,i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x33700000 0x0 0x1000>;
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&i2c_clk>;
status ="disabled";
};
i2c1: i2c1@33701000{
compatible = "ctc,i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x33701000 0x0 0x1000>;
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&i2c_clk>;
status ="disabled";
};
pcie: pcie@20000000 {
compatible = "centec,ctc5236-pcie";
reg = <0x0 0x20000000 0x0 0x10000000
0x0 0x30000000 0x0 0x1000>;
reg-names = "cfg", "ctrl";
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
device_type = "pci";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "msi","aer","pme";
msi-parent = <&pcie>;
bus-range = <0 0xff>;
ranges = <0x43000000 0 0x00000000 0 0x40000000 0 0x40000000>;
num-lanes = <1>;
ctc,sysctrl = <&sysctrl>;
status ="disabled";
};
wtd0: wtd0@33500000{
compatible = "arm,sp805-wdt", "arm,primecell";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x33500000 0x0 0x1000>;
clocks = <&wdog_clk>, <&sup_clk>;
clock-names = "wdog_clk", "apb_pclk";
ctc,sysctrl = <&sysctrl>;
interrupts = <GIC_SPI 38 IRQ_TYPE_EDGE_RISING>;
status="disabled";
};
wtd1: wtd1@33501000{
compatible = "arm,sp805-wdt", "arm,primecell";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x0 0x33501000 0x0 0x1000>;
clocks = <&wdog_clk>, <&sup_clk>;
clock-names = "wdog_clk", "apb_pclk";
ctc,sysctrl = <&sysctrl>;
interrupts = <GIC_SPI 39 IRQ_TYPE_EDGE_RISING>;
status="disabled";
};
sdhci: sdhci@30400000 {
compatible = "centec,ctc5236-sdhci";
status = "disabled";
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mmc_clk>;
clock-names = "mmc_clk";
ctc,sysctrl = <&sysctrl>;
reg = <0x0 0x30400000 0x0 0x1000>;
};
timer0: timer0@33600000{
compatible = "snps,dw-apb-timer";
reg = <0x0 0x33600000 0x0 0x20>;
clocks = <&timer_clk>;
clock-names = "timer";
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
DivNum = <0x3c>;
status="disabled";
};
timer1: timer1@33600020{
compatible = "snps,dw-apb-timer";
reg = <0x0 0x33600020 0x0 0x20>;
clocks = <&timer_clk>;
clock-names = "timer";
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
DivNum = <0x3c>;
status="disabled";
};
pwm: pwm@33200240{
compatible = "centec-pwm";
ctc,sysctrl = <&sysctrl>;
#pwm-cells = <2>;
status="disabled";
};
fan: fan-ctc5236 {
compatible = "fan-ctc5236";
pwms = <&pwm 0 1000000>,
<&pwm 1 1000000>,
<&pwm 2 1000000>,
<&pwm 3 1000000>;
pwm-names = "pwm1","pwm2","pwm3","pwm4";
};
gpio0: gpio@33610000 {
compatible = "ctc,apb-gpio";
reg = <0x0 0x33610000 0x0 0x10000>;
#address-cells = <1>;
#size-cells = <0>;
porta: gpio-port@0 {
compatible = "ctc,apb-gpio-porta";
gpio-controller;
#gpio-cells = <2>;
ctc,nr-gpios = <16>;
reg = <0>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
};
portb: gpio-port@1 {
compatible = "ctc,apb-gpio-portb";
gpio-controller;
#gpio-cells = <2>;
ctc,nr-gpios = <18>;
reg = <1>;
interrupt-controller;
#interrupt-cells = <2>;
interrupts = <GIC_SPI 99 IRQ_TYPE_LEVEL_HIGH>;
};
};
pinctrl: pinctrl {
compatible = "ctc,ctc5236-pinctrl";
#address-cells = <0x2>;
#size-cells = <0x2>;
ctc,pinctrl-bank0 = <16>;
ctc,pinctrl-bank1 = <8>;
ctc,sysctrl = <&sysctrl>;
status = "okay";
};
};
};

View File

@ -0,0 +1,212 @@
/*
* dts file for Centec CTC5236(TsingMa) SoC E530-24X2C Board
*
* (C) Copyright 2004-2018 Centec Networks (suzhou) Co., LTD.
*
* liuht <liuht@centecnetworks.com>
*
* 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.
*/
/dts-v1/;
#include "ctc5236.dtsi"
/ {
model = " CTC5236(TsingMa) E530 Board";
compatible = "ctc5236,e530-ctc5236";
memory {
device_type = "memory";
reg = <0 0x80000000 0x0 0x40000000>;
};
chosen {
stdout-path = "serial0:115200n8";
};
aliases {
serial0 = &serial0;
serial1 = &serial1;
ethernet0 = &enet0;
ethernet1 = &enet1;
};
};
&serial0 {
status = "okay";
};
&serial1 {
status = "okay";
};
&mdio {
status = "okay";
phy0: ethernet-phy@0 {
index = <0x00>;
reg = <0x00>;
};
};
&enet0 {
status = "okay";
phy-handle = <&phy0>;
auto-nego-mode= "sgmii-mac";
};
&qspi {
status = "okay";
qspiflash: mx25u3235f@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
spi-cpha;
spi-cpol;
spi-max-frequency = <25000000>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x300000>;
};
partition@300000 {
label = "uboot-env";
reg = <0x300000 0x10000>;
};
partition@310000 {
label = "system";
reg = <0x310000 0x10000>;
};
partition@320000 {
label = "hw-info";
reg = <0x320000 0x10000>;
};
};
};
};
&spi {
status = "disabled";
pinctrl-names = "default";
pinctrl-0 = <&spi_pin>;
clock0: ad9559@1 {
compatible = "analog,ad9559";
reg = <1>;
spi-max-frequency = <25000000>;
};
};
&switch {
status = "okay";
};
&switch1 {
status = "okay";
};
&i2c0{
status = "okay";
clock-frequency = <400000>;
eeprom_0:eeprom_0@57 {
compatible = "atmel,24c64";
reg = <0x57>;
pagesize = <32>;
};
rtc_0:rtc_0@32{
compatible = "sd2405";
reg = <0x32>;
};
};
&i2c1{
status = "okay";
clock-frequency = <400000>;
};
&ehci0 {
status = "okay";
};
&ohci0 {
status = "okay";
};
&wtd0{
status = "okay";
};
&wtd1{
status = "disabled";
};
&sdhci {
bus-width = <8>;
max-frequency = <100000000>;
non-removable;
no-sd;
no-sdio;
voltage-ranges = <3300 3300>;
status = "okay";
};
&timer0 {
status = "okay";
};
&soc {
ctc-irq@0 {
compatible = "centec,ctc-irq";
device_type = "ctc-irq";
interrupt-parent=<&porta>;
interrupts = < 0 IRQ_TYPE_LEVEL_LOW>,
< 1 IRQ_TYPE_LEVEL_LOW>,
<15 IRQ_TYPE_LEVEL_LOW>,
< 6 IRQ_TYPE_LEVEL_HIGH>,
< 7 IRQ_TYPE_LEVEL_HIGH>;
};
};
&pwm {
pinctrl-names = "default";
pinctrl-0 = <&pwm0_pin>;
status = "okay";
};
&pinctrl {
spi {
spi_pin: spi_pin {
status = "disabled";
ctc,pins = <0 0 PIN_FUNC_SPI>,
<0 2 PIN_FUNC_SPI>,
<0 3 PIN_FUNC_SPI>,
<0 5 PIN_FUNC_SPI>;
};
};
pwm0 {
pwm0_pin: pwm0_pin {
ctc,pins = <0 8 PIN_FUNC_PWM>,
<0 9 PIN_FUNC_PWM>,
<0 10 PIN_FUNC_PWM>,
<0 11 PIN_FUNC_PWM>,
<0 12 PIN_FUNC_PWM>,
<0 13 PIN_FUNC_PWM>,
<0 14 PIN_FUNC_PWM>,
<0 15 PIN_FUNC_PWM>;
};
};
};

View File

@ -0,0 +1,19 @@
/*
* This header provides constants for most IRQ bindings.
*
* Most IRQ bindings include a flags cell as part of the IRQ specifier.
* In most cases, the format of the flags cell uses the standard values
* defined in this header.
*/
#ifndef _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H
#define _DT_BINDINGS_INTERRUPT_CONTROLLER_IRQ_H
#define IRQ_TYPE_NONE 0
#define IRQ_TYPE_EDGE_RISING 1
#define IRQ_TYPE_EDGE_FALLING 2
#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)
#define IRQ_TYPE_LEVEL_HIGH 4
#define IRQ_TYPE_LEVEL_LOW 8
#endif

View File

@ -0,0 +1 @@
obj-m = ctc5236-mc.o

View File

@ -0,0 +1,279 @@
/* Centec TsingMa Memory Controller Driver
*
* Author: lius <lius@centecnetworks.com>
*
* Copyright 2002-2019, Centec Networks (Suzhou) Co., Ltd.
*
*
* 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.
*
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ctype.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/io.h>
struct ctc5236_mc {
struct device *dev;
void __iomem *base;
int irq;
};
/* DDR interrupt enable register */
#define DDR_ERR_INT_EN 0xF0
/* DDR interrupt status register */
#define DDR_ERR_INT_STATUS 0xF4
/* over top-bound info register*/
#define DDR_ERR_INT_OVER_TOPBOUND_L 0xF8
#define DDR_ERR_INT_OVER_TOPBOUND_H 0xFC
#define DDR_PORT0_ERR_INT_STATUS 0x1
#define DDR_PORT1_ERR_INT_STATUS 0x2
#define DDR_PORT2_ERR_INT_STATUS 0x3
#define DDR_PORT3_ERR_INT_STATUS 0x4
#define DDR_ERR_ECC_INT_STATUS 0x10000
#define DDR_ERR_WR_PORT_REC_UNDERFLOW 0x20000
#define DDR_ERR_WR_PORT_REC_OVERFLOW 0x40000
#define DDR_ERR_RD_PORT_REC_UNDERFLOW 0x80000
#define DDR_ERR_RD_PORT_REC_OVERFLOW 0x100000
#define DDR_PORT0_STATUS 0xB0
#define DDR_PORT1_STATUS 0xB4
#define DDR_PORT2_STATUS 0xB8
#define DDR_PORT3_STATUS 0xBC
#define DDR_ERR_OVER_TOPBOUND 0x20000
#define DDR_ERR_WCMDQ_OVER 0x40000
#define DDR_ERR_WCMDQ_UNDER 0x80000
#define DDR_ERR_WDATAQ_OVER 0x100000
#define DDR_ERR_WDATAQ_UNDER 0x200000
#define DDR_ERR_WESPQ_OVER 0x400000
#define DDR_ERR_WESPQ_UNDER 0x800000
#define DDR_ERR_WINFOQ_OVER 0x1000000
#define DDR_ERR_WINFOQ_UNDER 0x2000000
#define DDR_ERR_RCMDQ_OVER 0x4000000
#define DDR_ERR_RCMDQ_UNDER 0x8000000
#define DDR_ERR_RDATAQ_OVER 0x10000000
#define DDR_ERR_RDATAQ_UNDER 0x20000000
#define DDR_ERR_RESPQ_OVER 0x40000000
#define DDR_ERR_RESPQ_UNDER 0x80000000
#define DDR_PORT0_BASE 0xB0
#define DDR_PORT1_BASE 0xB4
#define DDR_PORT2_BASE 0xB8
#define DDR_PORT3_BASE 0xBc
#define DDR_PORT0 0
#define DDR_PORT1 1
#define DDR_PORT2 2
#define DDR_PORT3 3
static int port_err_status(int status, int port, void *dev_id)
{
int id = port;
unsigned long temp = 0;
unsigned int addr_h = 0;
unsigned int addr_l = 0;
struct ctc5236_mc *mci = dev_id;
/*the reason of port interrupt */
if (status & DDR_ERR_OVER_TOPBOUND) {
/* get low 32-bit address */
addr_l = readl(mci->base + DDR_ERR_INT_OVER_TOPBOUND_L);
/* get high 2-bit address */
addr_h = readl(mci->base + DDR_ERR_INT_OVER_TOPBOUND_H);
temp = (addr_l | (((unsigned long)((addr_h >> 12) & 0x3)) << 32)
);
pr_emerg("ERROR:port%d is out of top-bound range!\n"
"The error address is 0x%p\n",
id, (void *)temp);
}
if (status & DDR_ERR_WCMDQ_OVER)
pr_err("ERROR:port%d write command queue is overflow!\n", id);
if (status & DDR_ERR_WCMDQ_UNDER)
pr_err("ERROR:port%d write command queue is underflow!\n", id);
if (status & DDR_ERR_WDATAQ_OVER)
pr_err("ERROR:port%d write data queue is overflow!\n", id);
if (status & DDR_ERR_WDATAQ_UNDER)
pr_err("ERROR:port%d write data queue is underflow!\n", id);
if (status & DDR_ERR_WESPQ_OVER)
pr_err("ERROR:port%d write response queue is overflow!\n", id);
if (status & DDR_ERR_WESPQ_UNDER)
pr_err("ERROR:port%d write response queue is underflow!\n", id);
if (status & DDR_ERR_WINFOQ_OVER)
pr_err("ERROR:port%d write info queue is overflow!\n", id);
if (status & DDR_ERR_WINFOQ_UNDER)
pr_err("ERROR:port%d write info queue is underflow!\n", id);
if (status & DDR_ERR_RCMDQ_OVER)
pr_err("ERROR:port%d read command queue is overflow!\n", id);
if (status & DDR_ERR_RCMDQ_UNDER)
pr_err("ERROR:port%d read command queue is underflow!\n", id);
if (status & DDR_ERR_RDATAQ_OVER)
pr_err("ERROR:port%d read data queue is overflow!\n", id);
if (status & DDR_ERR_RDATAQ_UNDER)
pr_err("ERROR:port%d read data queue is underflow!\n", id);
if (status & DDR_ERR_RESPQ_OVER)
pr_err("ERROR:port%d read response queue is overflow!\n", id);
if (status & DDR_ERR_RESPQ_UNDER)
pr_err("ERROR:port%d read response queue is underflow!\n", id);
return 1;
}
static irqreturn_t ctc_mc_err_handler(int irq, void *dev_id)
{
struct ctc5236_mc *mci = dev_id;
unsigned int status;
unsigned int ret = 0;
/* get interrupt status */
status = readl(mci->base + DDR_ERR_INT_STATUS);
if (status & DDR_PORT0_ERR_INT_STATUS) {
ret = readl(mci->base + DDR_PORT0_BASE);
port_err_status(ret, DDR_PORT0, mci);
}
if (status & DDR_PORT1_ERR_INT_STATUS) {
ret = readl(mci->base + DDR_PORT1_BASE);
port_err_status(ret, DDR_PORT1, mci);
}
if (status & DDR_PORT2_ERR_INT_STATUS) {
ret = readl(mci->base + DDR_PORT2_BASE);
port_err_status(ret, DDR_PORT2, mci);
}
if (status & DDR_PORT3_ERR_INT_STATUS) {
ret = readl(mci->base + DDR_PORT3_BASE);
port_err_status(ret, DDR_PORT3, mci);
}
if (status & DDR_ERR_ECC_INT_STATUS)
pr_err("ERROR:The ecc more than 1-bit error !\n");
if (status & DDR_ERR_WR_PORT_REC_UNDERFLOW)
pr_err("ERROR:MPARB wr_port_rec FIFO is underflow!\n");
if (status & DDR_ERR_WR_PORT_REC_OVERFLOW)
pr_err("ERROR:MPARB wr_port_rec FIFO is overflow!\n");
if (status & DDR_ERR_RD_PORT_REC_UNDERFLOW)
pr_err("ERROR:MPARB rd_port_rec FIFO is underflow!\n");
if (status & DDR_ERR_RD_PORT_REC_OVERFLOW)
pr_err("ERROR:MPARB rd_port_rec FIFO is underflow!\n");
/* disable DDR interrupt */
writel(0x0, mci->base + DDR_ERR_INT_EN);
return IRQ_HANDLED;
}
static const struct of_device_id ctc5236_ddr_ctrl_of_match[] = {
{
.compatible = "ctc,ctc5236-ddr-ctrl",
},
{},
};
MODULE_DEVICE_TABLE(of, ctc5236_ddr_ctrl_of_match);
static int ctc5236_mc_probe(struct platform_device *pdev)
{
const struct of_device_id *id;
struct ctc5236_mc *mci;
int ret;
id = of_match_device(ctc5236_ddr_ctrl_of_match, &pdev->dev);
if (!id)
return -ENODEV;
mci = kzalloc(sizeof(*mci), GFP_KERNEL);
if (!mci)
return -ENODEV;
mci->base = devm_ioremap_resource(&pdev->dev, pdev->resource);
if (IS_ERR(mci->base))
return PTR_ERR(mci->base);
mci->irq = platform_get_irq(pdev, 0);
ret =
devm_request_irq(&pdev->dev, mci->irq, ctc_mc_err_handler, 0,
dev_name(&pdev->dev), mci);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to request irq %d\n", mci->irq);
goto err;
}
return 0;
err:
dev_err(&pdev->dev, "Probe Failed!\n");
return ret;
}
static int ctc5236_mc_remove(struct platform_device *pdev)
{
struct ctc5236_mc *mci = platform_get_drvdata(pdev);
devm_iounmap(&pdev->dev, mci->base);
devm_free_irq(&pdev->dev, mci->irq, mci);
kfree(mci);
return 0;
}
static struct platform_driver ctc5236_mc_driver = {
.probe = ctc5236_mc_probe,
.remove = ctc5236_mc_remove,
.driver = {
.name = "ctc5236_mc",
.of_match_table = ctc5236_ddr_ctrl_of_match,
},
};
static int __init ctc5236_mc_init(void)
{
return platform_driver_register(&ctc5236_mc_driver);
}
static void __exit ctc5236_mc_exit(void)
{
platform_driver_unregister(&ctc5236_mc_driver);
}
module_init(ctc5236_mc_init);
module_exit(ctc5236_mc_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Centec Network");
MODULE_DESCRIPTION("Centec TsingMa memory controller driver");

View File

@ -0,0 +1 @@
obj-m = ctc5236_switch.o

View File

@ -0,0 +1,324 @@
/* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
* Wangyb <wangyb@centecnetworks.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <../include/ctc5236_switch.h>
struct ctc_access_t *access;
#define SWITCH_DTS_OFFSET 0x1000
int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value)
{
union ctc_switch_cmd_status_u_t cmd_status_u;
u32 timeout = 0x6400;
u32 cmd_len = 0;
u8 index = 0;
if (!p_value) {
pr_err("switch read:value buffer is NULL!\n");
return -1;
}
/* switch only have 16 databuf, len must not exceed 16 */
if (len > 16 || len == 0) {
pr_err("switch read: length error! len = %d\n", len);
return -1;
}
/* cmdDataLen must be power of 2 */
if ((len & (len - 1)) == 0) {
cmd_len = len;
} else {
cmd_len = len;
do {
cmd_len++;
} while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
}
/* 1. write CmdStatusReg */
memset(&cmd_status_u, 0, sizeof(union ctc_switch_cmd_status_u_t));
cmd_status_u.cmd_status.cmdReadType = 1;
/* normal operate only support 1 entry */
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len;
cmd_status_u.cmd_status.cmdDataLen = len;
writel(cmd_status_u.val, &access->cmd_status);
/* 2. write AddrReg */
writel(offset, &access->addr);
/* 3. polling status and check */
cmd_status_u.val = readl(&access->cmd_status);
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout))
cmd_status_u.val = readl(&access->cmd_status);
/* 4. check cmd done */
if (!(cmd_status_u.cmd_status.reqProcDone)) {
pr_err("switch read error! cmd_status = %x\n",
cmd_status_u.val);
return -1;
}
/* 5. check pcie read status */
if (cmd_status_u.cmd_status.reqProcError != 0) {
pr_err("pci read error! cmd_status = %x, offset = 0x%x\n",
cmd_status_u.val, offset);
return -1;
}
/* 6. read data from buffer */
for (index = 0; index < len; index++)
p_value[index] = readl(&access->data[index]);
return 0;
}
int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value)
{
union ctc_switch_cmd_status_u_t cmd_status_u;
u32 timeout = 0x6400; /* need to be confirmed */
u32 cmd_len = 0;
u8 index = 0;
if (!p_value) {
pr_err("switch write:value buffer is NULL!\n");
return -1;
}
/* switch only have 16 databuf, len must not exceed 16 */
if (len > 16 || len == 0) {
pr_err("switch write length error! len = %d\n", len);
return -1;
}
/* cmdDataLen must be power of 2 */
if ((len & (len - 1)) == 0) {
cmd_len = len;
} else {
cmd_len = len;
do {
cmd_len++;
} while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
}
/* 1. write CmdStatusReg */
memset(&cmd_status_u, 0, sizeof(struct ctc_switch_cmd_status_t));
cmd_status_u.cmd_status.cmdReadType = 0;
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len;
/* Notice: for 1 entry op, cmdDatalen eq cmdEntryWords,
* but for mutil entry, len = cmd_len
*/
cmd_status_u.cmd_status.cmdDataLen = len;
writel(cmd_status_u.val, &access->cmd_status);
/* 2. write AddrReg */
writel(offset, &access->addr);
/* 3. write data into databuffer */
for (index = 0; index < len; index++)
writel(p_value[index], &access->data[index]);
/* 4. polling status and check */
cmd_status_u.val = readl(&access->cmd_status);
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout))
cmd_status_u.val = readl(&access->cmd_status);
/* 5. check cmd done */
if (!(cmd_status_u.cmd_status.reqProcDone)) {
pr_err("switch write error! cmd_status = %x\n",
cmd_status_u.val);
return -1;
}
/* 6. check switch read status */
if (cmd_status_u.cmd_status.reqProcError != 0) {
pr_err("switch write error! cmd_status = %x, offset=0x%x\n",
cmd_status_u.val, offset);
return -1;
}
return 0;
}
static int
_sys_tsingma_peri_get_temp_with_code(u8 lchip, u32 temp_code, u32 *p_temp_val)
{
u16 temp_mapping_tbl[SYS_TSINGMA_TEMP_TABLE_NUM + 1] = {
804, 801, 798, 795, 792, 790, 787, 784, 781, 778,
775, 772, 769, 766, 763, 761, 758, 755, 752, 749,
746, 743, 740, 737, 734, 731, 728, 725, 722, 719,
717, 714, 711, 708, 705, 702, 699, 696, 693, 690,
687, 684, 681, 678, 675, 672, 669, 666, 663, 660,
658, 655, 652, 649, 646, 643, 640, 637, 634, 631,
628, 625, 622, 619, 616, 613, 610, 607, 604, 601,
599, 596, 593, 590, 587, 584, 581, 578, 575, 572,
569, 566, 563, 560, 557, 554, 551, 548, 545, 542,
540, 537, 534, 531, 528, 525, 522, 519, 516, 513,
510, 507, 504, 501, 498, 495, 492, 489, 486, 483,
481, 478, 475, 472, 469, 466, 463, 460, 457, 454,
451, 448, 445, 442, 439, 436, 433, 430, 427, 424,
421, 418, 415, 412, 409, 406, 403, 400, 397, 394,
391, 388, 385, 382, 379, 376, 373, 370, 367, 364,
361, 358, 355, 352, 349, 346, 343, 340, 337, 334,
331, 328, 325, 322, 319, 316, 0
};
u8 index = 0;
for (index = 0; index < SYS_TSINGMA_TEMP_TABLE_NUM; index++) {
if ((temp_code <= temp_mapping_tbl[index])
&& (temp_code > temp_mapping_tbl[index + 1])) {
break;
}
}
if (index < 39)
*p_temp_val = 40 - index + (1 << 31);
else
*p_temp_val = index - 40;
return 0;
}
int get_switch_temperature(void)
{
int temperature;
u32 value, offset, p_value = 0;
u32 timeout = SYS_TSINGMA_SENSOR_TIMEOUT;
value = 0x310c7;
offset = 0xf * 4;
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
/*config RTHMC_RST=1 */
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000010 0x00000010 */
offset = 0x10 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(4);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
/*wait RTHMC_RST=1 */
/*read tbl-reg OmcMem 0x10 offset 0x0 */
timeout = SYS_TSINGMA_SENSOR_TIMEOUT;
offset = 0x10 * 4;
while (timeout) {
timeout--;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
if ((BIT(4) & value) == 0)
break;
msleep(1);
}
if (timeout == 0)
return 0xffff;
/*config ENBIAS=1£¬ENVR=1£¬ENAD=1 */
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x02000007 0x03000007 */
offset = 0x11 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(0) | BIT(1) | BIT(2) | BIT(25);
value &= ~BIT(24);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
msleep(1);
/*set RTHM_MODE=1,RSAMPLE_DONE_INTEN=1,RDUMMY_THMRD=1,RV_SAMPLE_EN=1 */
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000203 0x00000003 */
/*mask_write tbl-reg OmcMem 0x8 offset 0x0 0x00000004 0x00000004 */
/*mask_write tbl-reg OmcMem 0x12 offset 0x0 0x00000001 0x00000001 */
offset = 0x10 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(0) | BIT(1) | BIT(9);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
offset = 0x8 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(2);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
offset = 0x12 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(0);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000001 0x00000001 */
offset = 0x10 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(0);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
msleep(1);
/*mask_write tbl-reg OmcMem 0x12 offset 0x0 0x00000001 0x00000001 */
offset = 0x12 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(0);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
/*Wait((mask_read tbl-reg OmcMem 0xa offset 0x0 0x00000004) =1) */
timeout = SYS_TSINGMA_SENSOR_TIMEOUT;
offset = 0xa * 4;
while (timeout) {
timeout--;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
if (value & BIT(2))
break;
msleep(1);
}
if (timeout == 0)
return 0xffff;
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x00000006 0x00000006 */
offset = 0x11 * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
value |= BIT(1) | BIT(2);
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
msleep(10);
/*read-reg OmcMem 0xd offset 0x0 */
offset = 0xd * 4;
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
_sys_tsingma_peri_get_temp_with_code(0, value, &p_value);
temperature = p_value & ~BIT(31);
if ((p_value & BIT(31)) == 0)
return temperature;
else
return -temperature;
}
EXPORT_SYMBOL_GPL(get_switch_temperature);
static int ctc_switch_probe(struct platform_device *pdev)
{
struct resource *iomem;
void __iomem *ioaddr;
resource_size_t start;
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
start = iomem->start - 0x1000;
ioaddr = devm_ioremap(&pdev->dev, start, resource_size(iomem));
if (IS_ERR(ioaddr))
return -1;
access = (struct ctc_access_t *) ioaddr;
return 0;
}
static const struct of_device_id ctc_switch_of_match[] = {
{.compatible = "centec,switch"},
{}
};
MODULE_DEVICE_TABLE(of, ctc_switch_of_match);
static struct platform_driver ctc_switch_driver = {
.driver = {
.name = "ctc-switch",
.of_match_table = ctc_switch_of_match,
},
.probe = ctc_switch_probe,
};
module_platform_driver(ctc_switch_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:switch");

View File

@ -0,0 +1 @@
obj-m = ctc_wdt.o

View File

@ -0,0 +1,398 @@
/* drivers/char/watchdog/ctc-wdt.c
*
* Watchdog driver for CTC TSINGMA, based on ARM SP805 watchdog module
*
* Copyright (C) 2010 ST Microelectronics
* Viresh Kumar <vireshk@kernel.org>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/device.h>
#include <linux/resource.h>
#include <linux/amba/bus.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include "../include/sysctl.h"
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
/* default timeout in seconds */
#define DEFAULT_TIMEOUT 60
#define MODULE_NAME "ctc-wdt"
/* watchdog register offsets and masks */
#define WDTLOAD 0x000
#define LOAD_MIN 0x00000001
#define LOAD_MAX 0xFFFFFFFF
#define WDTVALUE 0x004
#define WDTCONTROL 0x008
/* control register masks */
#define INT_ENABLE (1 << 0)
#define RESET_ENABLE (1 << 1)
#define WDTINTCLR 0x00C
#define WDTRIS 0x010
#define WDTMIS 0x014
#define INT_MASK (1 << 0)
#define WDTLOCK 0xC00
#define UNLOCK 0x1ACCE551
#define LOCK 0x00000001
/* TsingMa SoC */
#define WDTCLK_MAX 500000000UL
/**
* struct ctc_wdt: ctc wdt device structure
* @wdd: instance of struct watchdog_device
* @lock: spin lock protecting dev structure and io access
* @base: base address of wdt
* @clk: clock structure of wdt
* @adev: amba device structure of wdt
* @status: current status of wdt
* @load_val: load value to be set for current timeout
*/
struct ctc_wdt {
struct watchdog_device wdd;
spinlock_t lock;
void __iomem *base;
struct clk *clk;
struct amba_device *adev;
unsigned int load_val;
struct regmap *regmap_base;
};
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Set to 1 to keep watchdog running after device release");
/* This routine finds load value that will reset system in required timeout */
static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
u64 load, rate;
rate = clk_get_rate(wdt->clk);
/*
* ctc wdt runs counter with given value twice, after the end of first
* counter it gives an interrupt and then starts counter again. If
* interrupt already occurred then it resets the system. This is why
* load is half of what should be required.
*/
load = div_u64(rate, 2) * timeout - 1;
load = (load > LOAD_MAX) ? LOAD_MAX : load;
load = (load < LOAD_MIN) ? LOAD_MIN : load;
spin_lock(&wdt->lock);
wdt->load_val = load;
/* roundup timeout to closest positive integer value */
wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
spin_unlock(&wdt->lock);
return 0;
}
/* returns number of seconds left for reset to occur */
static unsigned int wdt_timeleft(struct watchdog_device *wdd)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
u64 load, rate;
rate = clk_get_rate(wdt->clk);
spin_lock(&wdt->lock);
load = readl_relaxed(wdt->base + WDTVALUE);
/*If the interrupt is inactive then time left is WDTValue + WDTLoad. */
if (!(readl_relaxed(wdt->base + WDTRIS) & INT_MASK))
load += wdt->load_val + 1;
spin_unlock(&wdt->lock);
return div_u64(load, rate);
}
static int wdt_config(struct watchdog_device *wdd, bool ping)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
int ret;
if (!ping) {
ret = clk_prepare_enable(wdt->clk);
if (ret) {
dev_err(&wdt->adev->dev, "clock enable fail");
return ret;
}
}
spin_lock(&wdt->lock);
writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
writel_relaxed(wdt->load_val, wdt->base + WDTLOAD);
writel_relaxed(INT_MASK, wdt->base + WDTINTCLR);
if (!ping)
writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base +
WDTCONTROL);
writel_relaxed(LOCK, wdt->base + WDTLOCK);
/* Flush posted writes. */
readl_relaxed(wdt->base + WDTLOCK);
spin_unlock(&wdt->lock);
return 0;
}
static int wdt_ping(struct watchdog_device *wdd)
{
return wdt_config(wdd, true);
}
/* enables watchdog timers reset */
static int wdt_enable(struct watchdog_device *wdd)
{
return wdt_config(wdd, false);
}
/* disables watchdog timers reset */
static int wdt_disable(struct watchdog_device *wdd)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
spin_lock(&wdt->lock);
writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
writel_relaxed(0, wdt->base + WDTCONTROL);
writel_relaxed(LOCK, wdt->base + WDTLOCK);
/* Flush posted writes. */
readl_relaxed(wdt->base + WDTLOCK);
spin_unlock(&wdt->lock);
clk_disable_unprepare(wdt->clk);
return 0;
}
static int wdt_restart(struct watchdog_device *wdd, unsigned long action,
void *cmd)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
spin_lock(&wdt->lock);
writel_relaxed(UNLOCK, wdt->base + WDTLOCK);
writel_relaxed(0, wdt->base + WDTCONTROL);
writel_relaxed(1, wdt->base + WDTLOAD);
writel_relaxed(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
writel_relaxed(LOCK, wdt->base + WDTLOCK);
spin_unlock(&wdt->lock);
mdelay(100);
return 0;
}
static int wdt_set_pretimeout(struct watchdog_device *wdd,
unsigned int new_pretimeout)
{
struct ctc_wdt *wdt = watchdog_get_drvdata(wdd);
u64 load, rate;
rate = clk_get_rate(wdt->clk);
load = rate * new_pretimeout - 1;
load = (load > LOAD_MAX) ? LOAD_MAX : load;
load = (load < LOAD_MIN) ? LOAD_MIN : load;
spin_lock(&wdt->lock);
wdt->load_val = load;
/* roundup timeout to closest positive integer value */
wdd->pretimeout = div_u64((load + 1) + (rate / 2), rate);
spin_unlock(&wdt->lock);
return 0;
}
static irqreturn_t ctc_wdt_irq(int irq, void *dev_id)
{
struct ctc_wdt *wdt = dev_id;
watchdog_notify_pretimeout(&wdt->wdd);
return IRQ_HANDLED;
}
static const struct watchdog_info wdt_info = {
.options =
WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_PRETIMEOUT,
.identity = MODULE_NAME,
};
static const struct watchdog_ops wdt_ops = {
.owner = THIS_MODULE,
.start = wdt_enable,
.stop = wdt_disable,
.ping = wdt_ping,
.set_timeout = wdt_setload,
.get_timeleft = wdt_timeleft,
.restart = wdt_restart,
.set_pretimeout = wdt_set_pretimeout,
};
static int ctc_wdt_probe(struct amba_device *adev, const struct amba_id *id)
{
struct ctc_wdt *wdt;
int ret = 0;
u64 rate;
unsigned int fdc;
wdt = devm_kzalloc(&adev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt) {
ret = -ENOMEM;
goto err;
}
wdt->base = devm_ioremap_resource(&adev->dev, &adev->res);
if (IS_ERR(wdt->base))
return PTR_ERR(wdt->base);
wdt->clk = devm_clk_get(&adev->dev, NULL);
if (IS_ERR(wdt->clk)) {
dev_warn(&adev->dev, "Clock not found\n");
ret = PTR_ERR(wdt->clk);
goto err;
}
wdt->regmap_base = syscon_regmap_lookup_by_phandle(adev->dev.of_node,
"ctc,sysctrl");
if (IS_ERR(wdt->regmap_base))
return PTR_ERR(wdt->regmap_base);
/*
* TsingMa SoC wdt reference clock is obtained by clockSub frequency
* division,which is 500Mhz.So we need to set the frequency division
* register according to the configured clock.
*/
rate = clk_get_rate(wdt->clk);
if (rate < 0 || rate > WDTCLK_MAX) {
dev_err(&adev->dev, "Clock out of range\n");
goto err;
}
fdc = div_u64(WDTCLK_MAX, rate);
regmap_write(wdt->regmap_base, offsetof(struct SysCtl_regs, SysWdt0Cnt),
fdc);
regmap_write(wdt->regmap_base, offsetof(struct SysCtl_regs, SysWdt1Cnt),
fdc);
wdt->adev = adev;
wdt->wdd.info = &wdt_info;
wdt->wdd.ops = &wdt_ops;
wdt->wdd.parent = &adev->dev;
spin_lock_init(&wdt->lock);
watchdog_set_nowayout(&wdt->wdd, nowayout);
watchdog_set_drvdata(&wdt->wdd, wdt);
wdt_setload(&wdt->wdd, DEFAULT_TIMEOUT);
ret = devm_request_irq(&adev->dev, adev->irq[0], ctc_wdt_irq,
0, "ctc-wdt", wdt);
if (ret < 0) {
dev_err(&adev->dev, "devm_request_irq() failed: %d\n", ret);
goto err;
}
ret = watchdog_register_device(&wdt->wdd);
if (ret) {
dev_err(&adev->dev, "watchdog_register_device() failed: %d\n",
ret);
goto err;
}
amba_set_drvdata(adev, wdt);
dev_info(&adev->dev, "registration successful\n");
return 0;
err:
dev_err(&adev->dev, "Probe Failed!!!\n");
return ret;
}
static int ctc_wdt_remove(struct amba_device *adev)
{
struct ctc_wdt *wdt = amba_get_drvdata(adev);
watchdog_unregister_device(&wdt->wdd);
watchdog_set_drvdata(&wdt->wdd, NULL);
return 0;
}
static int __maybe_unused ctc_wdt_suspend(struct device *dev)
{
struct ctc_wdt *wdt = dev_get_drvdata(dev);
if (watchdog_active(&wdt->wdd))
return wdt_disable(&wdt->wdd);
return 0;
}
static int __maybe_unused ctc_wdt_resume(struct device *dev)
{
struct ctc_wdt *wdt = dev_get_drvdata(dev);
if (watchdog_active(&wdt->wdd))
return wdt_enable(&wdt->wdd);
return 0;
}
static SIMPLE_DEV_PM_OPS(ctc_wdt_dev_pm_ops, ctc_wdt_suspend, ctc_wdt_resume);
static struct amba_id ctc_wdt_ids[] = {
/* Centec TsingMa SoC WDT ID */
{
.id = 0x001bb824,
.mask = 0x00ffffff,
},
{0, 0},
};
MODULE_DEVICE_TABLE(amba, ctc_wdt_ids);
static struct amba_driver ctc_wdt_driver = {
.drv = {
.name = MODULE_NAME,
.pm = &ctc_wdt_dev_pm_ops,
},
.id_table = ctc_wdt_ids,
.probe = ctc_wdt_probe,
.remove = ctc_wdt_remove,
};
module_amba_driver(ctc_wdt_driver);
MODULE_AUTHOR("lius <lius@centecnetworks.com>");
MODULE_DESCRIPTION("ARM CTC Watchdog Driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,3 @@
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/tsingma-bsp/src/ctc5236_switch/Module.symvers
obj-m = ctcmac.o ctcmac_test.o ctc5236_mdio.o

View File

@ -0,0 +1,195 @@
/* Centec cpu_mac Ethernet Driver -- cpu_mac controller implementation
* Provides Bus interface for MIIM regs
*
* Author: liuht <liuht@centecnetworks.com>
*
* Copyright 2002-2018, Centec Networks (Suzhou) Co., Ltd.
*
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_mdio.h>
#include <linux/of_platform.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/in.h>
#include <linux/net_tstamp.h>
#include <linux/mii.h>
#include <linux/iopoll.h>
#include <asm/io.h>
#include "ctcmac.h"
#include "ctcmac_reg.h"
struct ctc_mdio_priv {
void __iomem *map;
struct mdio_soc_regs *mdio_reg;
};
static int ctc_mdio_write(struct mii_bus *bus, int mii_id, int reg, u16 value)
{
int ret = 0;
u32 cmd = 0;
u32 tmp = 0;
struct ctc_mdio_priv *priv = (struct ctc_mdio_priv *)bus->priv;
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
| CTCMAC_MDIO_CMD_OPCODE(1) | CTCMAC_MDIO_CMD_DATA(value);
writel(cmd, &priv->mdio_reg->mdio_soc_cmd_0[0]);
writel(1, &priv->mdio_reg->mdio_soc_cmd_0[1]);
ret = readl_poll_timeout(&priv->mdio_reg->mdio_soc_status_0,
tmp, tmp & CTCMAC_MDIO_STAT(1), 1000, 10000);
if (ret < 0)
return -1;
return 0;
}
static int ctc_mdio_read(struct mii_bus *bus, int mii_id, int reg)
{
int ret = 0;
u32 cmd = 0;
u32 status;
int value = 0;
struct ctc_mdio_priv *priv = (struct ctc_mdio_priv *)bus->priv;
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
| CTCMAC_MDIO_CMD_OPCODE(2);
writel(cmd, &priv->mdio_reg->mdio_soc_cmd_0[0]);
writel(1, &priv->mdio_reg->mdio_soc_cmd_0[1]);
ret = readl_poll_timeout(&priv->mdio_reg->mdio_soc_status_0,
status, status & CTCMAC_MDIO_STAT(1), 1000,
10000);
if (ret < 0) {
pr_err("ctc_mdio_read1\n");
return -1;
}
value = (readl(&priv->mdio_reg->mdio_soc_status_0) & 0xffff);
return value;
}
static int ctc_mdio_reset(struct mii_bus *bus)
{
struct ctc_mdio_priv *priv = (struct ctc_mdio_priv *)bus->priv;
writel(0x91f, &priv->mdio_reg->mdio_soc_cfg_0);
return 0;
}
static const struct of_device_id ctc_mdio_match[] = {
{
.compatible = "ctc,mdio",
},
{},
};
MODULE_DEVICE_TABLE(of, ctc_mdio_match);
static int ctc_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct resource res;
struct ctc_mdio_priv *priv;
struct mii_bus *new_bus;
int err;
new_bus = mdiobus_alloc_size(sizeof(*priv));
if (!new_bus)
return -ENOMEM;
priv = new_bus->priv;
new_bus->name = "CTC MII Bus", new_bus->read = &ctc_mdio_read;
new_bus->write = &ctc_mdio_write;
new_bus->reset = &ctc_mdio_reset;
err = of_address_to_resource(np, 0, &res);
if (err < 0) {
pr_err("Of address to resource fail %d!\n", err);
goto error;
}
snprintf(new_bus->id, MII_BUS_ID_SIZE, "%s@%llx", np->name,
(unsigned long long)res.start);
priv->map = of_iomap(np, 0);
if (!priv->map) {
err = -ENOMEM;
pr_err("of iomap fail %d!\n", err);
goto error;
}
priv->mdio_reg = (struct mdio_soc_regs *)priv->map;
new_bus->parent = &pdev->dev;
platform_set_drvdata(pdev, new_bus);
err = of_mdiobus_register(new_bus, np);
if (err) {
pr_err("register mdio bus fail %d!\n", err);
goto error;
}
return 0;
error:
if (priv->map)
iounmap(priv->map);
kfree(new_bus);
return err;
}
static int ctc_mdio_remove(struct platform_device *pdev)
{
struct device *device = &pdev->dev;
struct mii_bus *bus = dev_get_drvdata(device);
struct ctc_mdio_priv *priv = bus->priv;
mdiobus_unregister(bus);
iounmap(priv->map);
mdiobus_free(bus);
return 0;
}
static struct platform_driver ctc_mdio_driver = {
.driver = {
.name = "ctc_mdio",
.of_match_table = ctc_mdio_match,
},
.probe = ctc_mdio_probe,
.remove = ctc_mdio_remove,
};
module_platform_driver(ctc_mdio_driver);
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,307 @@
/*
* Centec cpu_mac Ethernet Driver -- cpu_mac controller implementation
* Provides Bus interface for MIIM regs
*
* Author: liuht <liuht@centecnetworks.com>
*
* Copyright 2002-2017, Centec Networks (Suzhou) Co., Ltd.
*
*
* 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.
*
*/
#ifndef __CTCMAC_H
#define __CTCMAC_H
#define TX_TIMEOUT (5 * HZ)
#define CTCMAC_DEFAULT_MTU 1500
#define CTCMAC_MIN_PKT_LEN 64
#define CTCMAC_TX_QUEUE_MAX 1
#define CTCMAC_RX_QUEUE_MAX 2
#define CTCMAC0_EXSRAM_BASE 0x0
#define CTCMAC1_EXSRAM_BASE 0x1800
#define CTCMAC_MAX_RING_SIZE 1023
#define CTCMAC_TX_RING_SIZE 1023
#define CTCMAC_RX_RING_SIZE 1023
#define CTCMAC_RX_BUFF_ALLOC 16
#define CTCMAC_INTERNAL_RING_SIZE 64
/* The maximum number of packets to be handled in one call of gfar_poll */
#define CTCMAC_NAIP_RX_WEIGHT 16
#define CTCMAC_NAIP_TX_WEIGHT 16
#define CTCMAC_RXB_SIZE 1024
#define CTCMAC_SKBFRAG_SIZE (CTCMAC_RXB_SIZE \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
#define CTCMAC_RXB_TRUESIZE 2048
#define BUF_ALIGNMENT 256
#define CTCMAC_JUMBO_FRAME_SIZE 9600
#define CTCMAC_TOKEN_PER_PKT 10
#define CTCMAC_TIMER_COMPENSATE 1
#define CTCMAC_NOR_RX1_R BIT(7)
#define CTCMAC_NOR_RX0_R BIT(6)
#define CTCMAC_NOR_RX1_D BIT(5)
#define CTCMAC_NOR_RX0_D BIT(4)
#define CTCMAC_NOR_TX_D BIT(3)
#define CTCMAC_NOR_AN_D BIT(2)
#define CTCMAC_NOR_LINK_DOWN BIT(1)
#define CTCMAC_NOR_LINK_UP BIT(0)
#define CTC_DDR_BASE 0x80000000
#define CSA_SGMII_MD_MASK 0x00000008
#define CSA_EN 0x00000001
/*Mask*/
/*CTCMAC_SGMII_CFG*/
#define CSC_REP_MASK 0x1fc00000
#define CSC_SMP_MASK 0x1fc00000
/*CTCMAC_SGMII_MON*/
#define CSM_ANST_MASK 0x00000007
#define CSC_1000M 0x00000000
#define CSC_100M 0x02400000
#define CSC_10M 0x18c00000
#define CTCMAC_DESC_INT_NUM 1
#define CTCMAC_SUPPORTED (SUPPORTED_10baseT_Full \
| SUPPORTED_100baseT_Full \
| SUPPORTED_1000baseT_Full \
| SUPPORTED_Autoneg)
#define CTCMAC_STATS_LEN (sizeof(struct ctcmac_pkt_stats) / sizeof(u64))
struct ctcmac_skb_cb {
unsigned int bytes_sent; /* bytes-on-wire (i.e. no FCB) */
};
#define CTCMAC_CB(skb) ((struct ctcmac_skb_cb *)((skb)->cb))
enum ctcmac_irqinfo_id {
CTCMAC_NORMAL = 0,
CTCMAC_FUNC,
CTCMAC_UNIT,
CTCMAC_NUM_IRQS
};
enum ctcmac_dev_state {
CTCMAC_DOWN = 1,
CTCMAC_RESETTING
};
enum ctcmac_int_type {
CTCMAC_INT_PACKET = 1,
CTCMAC_INT_DESC,
CTCMAC_INT_MAX
};
enum ctcmac_autoneg {
CTCMAC_AUTONEG_1000BASEX_M,
CTCMAC_AUTONEG_PHY_M,
CTCMAC_AUTONEG_MAC_M,
CTCMAC_AUTONEG_DISABLE,
CTCMAC_AUTONEG_MAX
};
/* Per TX queue stats */
struct txq_stats {
unsigned long tx_packets;
unsigned long tx_bytes;
};
struct ctcmac_tx_buff {
void *vaddr;
dma_addr_t dma;
u32 len;
u32 offset;
u8 alloc;
};
struct ctcmac_priv_tx_q {
spinlock_t txlock __aligned(SMP_CACHE_BYTES);
struct ctcmac_tx_buff tx_buff[CTCMAC_MAX_RING_SIZE + 1];
unsigned int num_txbdfree;
u16 tx_ring_size;
u16 qindex;
u16 next_to_alloc;
u16 next_to_clean;
struct txq_stats stats;
struct net_device *dev;
struct sk_buff **tx_skbuff;
};
/*Per RX queue stats */
struct rxq_stats {
unsigned long rx_packets;
unsigned long rx_bytes;
unsigned long rx_dropped;
};
struct ctcmac_rx_buff {
dma_addr_t dma;
struct page *page;
unsigned int page_offset;
};
struct ctcmac_priv_rx_q {
struct ctcmac_rx_buff *rx_buff __aligned(SMP_CACHE_BYTES);
struct net_device *ndev;
struct device *dev;
u16 rx_ring_size;
u16 qindex;
u16 next_to_clean;
u16 next_to_use;
u16 next_to_alloc;
struct sk_buff *skb;
struct rxq_stats stats;
u32 pps_limit;
u32 token, token_max;
u32 rx_trigger;
};
struct ctcmac_irqinfo {
unsigned int irq;
char name[32];
};
struct ctcmac_desc_cfg {
u8 err_type; /*used when err == 1 */
u8 err;
u8 eop;
u8 sop;
u32 size;
u32 addr_high;
u32 addr_low;
};
struct ctcmac_private {
spinlock_t reglock __aligned(SMP_CACHE_BYTES);
struct device *dev;
struct net_device *ndev;
void __iomem *iobase;
struct cpu_mac_regs __iomem *cpumac_reg;
struct cpu_mac_mems __iomem *cpumac_mem;
struct cpu_mac_unit_regs *cpumacu_reg;
u32 device_flags;
int irq_num;
int index;
struct ctcmac_priv_tx_q *tx_queue[CTCMAC_TX_QUEUE_MAX];
struct ctcmac_priv_rx_q *rx_queue[CTCMAC_RX_QUEUE_MAX];
unsigned long state;
unsigned int num_tx_queues;
unsigned int num_rx_queues;
/* PHY stuff */
phy_interface_t interface;
struct device_node *phy_node;
struct mii_bus *mii_bus;
int oldspeed;
int oldlink;
int oldduplex;
struct work_struct reset_task;
struct platform_device *ofdev;
struct napi_struct napi_rx;
struct napi_struct napi_tx;
struct ctcmac_irqinfo irqinfo[CTCMAC_NUM_IRQS];
int hwts_rx_en;
int hwts_tx_en;
u32 autoneg_mode;
u32 supported;
u32 msg_enable;
u32 int_type;
u8 dfe_enable;
struct timer_list token_timer;
};
struct ctcmac_pkt_stats {
u64 rx_good_ucast_bytes;
u64 rx_good_ucast_pkt;
u64 rx_good_mcast_bytes;
u64 rx_good_mcast_pkt;
u64 rx_good_bcast_bytes;
u64 rx_good_bcast_pkt;
u64 rx_good_pause_bytes;
u64 rx_good_pause_pkt;
u64 rx_good_pfc_bytes;
u64 rx_good_pfc_pkt;
u64 rx_good_control_bytes;
u64 rx_good_control_pkt;
u64 rx_fcs_error_bytes;
u64 rx_fcs_error_pkt;
u64 rx_mac_overrun_bytes;
u64 rx_mac_overrun_pkt;
u64 rx_good_63B_bytes;
u64 rx_good_63B_pkt;
u64 rx_bad_63B_bytes;
u64 rx_bad_63B_pkt;
u64 rx_good_mtu2B_bytes;
u64 rx_good_mtu2B_pkt;
u64 rx_bad_mtu2B_bytes;
u64 rx_bad_mtu2B_pkt;
u64 rx_good_jumbo_bytes;
u64 rx_good_jumbo_pkt;
u64 rx_bad_jumbo_bytes;
u64 rx_bad_jumbo_pkt;
u64 rx_64B_bytes;
u64 rx_64B_pkt;
u64 rx_127B_bytes;
u64 rx_127B_pkt;
u64 rx_255B_bytes;
u64 rx_255B_pkt;
u64 rx_511B_bytes;
u64 rx_511B_pkt;
u64 rx_1023B_bytes;
u64 rx_1023B_pkt;
u64 rx_mtu1B_bytes;
u64 rx_mtu1B_pkt;
u64 tx_ucast_bytes;
u64 tx_ucast_pkt;
u64 tx_mcast_bytes;
u64 tx_mcast_pkt;
u64 tx_bcast_bytes;
u64 tx_bcast_pkt;
u64 tx_pause_bytes;
u64 tx_pause_pkt;
u64 tx_control_bytes;
u64 tx_control_pkt;
u64 tx_fcs_error_bytes;
u64 tx_fcs_error_pkt;
u64 tx_underrun_bytes;
u64 tx_underrun_pkt;
u64 tx_63B_bytes;
u64 tx_63B_pkt;
u64 tx_64B_bytes;
u64 tx_64B_pkt;
u64 tx_127B_bytes;
u64 tx_127B_pkt;
u64 tx_255B_bytes;
u64 tx_255B_pkt;
u64 tx_511B_bytes;
u64 tx_511B_pkt;
u64 tx_1023B_bytes;
u64 tx_1023B_pkt;
u64 tx_mtu1_bytes;
u64 tx_mtu1_pkt;
u64 tx_mtu2_bytes;
u64 tx_mtu2_pkt;
u64 tx_jumbo_bytes;
u64 tx_jumbo_pkt;
u64 mtu1;
u64 mtu2;
};
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
obj-m = ehci-ctc.o

View File

@ -0,0 +1,423 @@
/*
* Centec platform ehci driver
*
* Copyright 2018 Liuht <liuht@centecnetworks.com>
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include <linux/acpi.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/usb.h>
#include <linux/usb/hcd.h>
#include <linux/usb/ehci_pdriver.h>
#include "ehci.h"
#define DRIVER_DESC "Centec EHCI platform driver"
#define EHCI_MAX_CLKS 4
#define EHCI_MAX_RSTS 4
#define hcd_to_ehci_priv(h) ((struct ehci_ctc_priv *)hcd_to_ehci(h)->priv)
struct ehci_ctc_priv {
struct clk *clks[EHCI_MAX_CLKS];
struct reset_control *rsts[EHCI_MAX_RSTS];
struct phy **phys;
int num_phys;
bool reset_on_resume;
};
static const char hcd_name[] = "ehci-ctc";
static int ehci_ctc_reset(struct usb_hcd *hcd)
{
struct platform_device *pdev = to_platform_device(hcd->self.controller);
struct usb_ehci_pdata *pdata = dev_get_platdata(&pdev->dev);
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
if (pdata->pre_setup) {
retval = pdata->pre_setup(hcd);
if (retval < 0)
return retval;
}
ehci->caps = hcd->regs + pdata->caps_offset;
retval = ehci_setup(hcd);
if (retval)
return retval;
if (pdata->no_io_watchdog)
ehci->need_io_watchdog = 0;
return 0;
}
static int ehci_ctc_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
int clk, ret, phy_num;
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
if (ret)
goto err_disable_clks;
}
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
ret = phy_init(priv->phys[phy_num]);
if (ret)
goto err_exit_phy;
ret = phy_power_on(priv->phys[phy_num]);
if (ret) {
phy_exit(priv->phys[phy_num]);
goto err_exit_phy;
}
}
return 0;
err_exit_phy:
while (--phy_num >= 0) {
phy_power_off(priv->phys[phy_num]);
phy_exit(priv->phys[phy_num]);
}
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
return ret;
}
static void ehci_ctc_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
int clk, phy_num;
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
phy_power_off(priv->phys[phy_num]);
phy_exit(priv->phys[phy_num]);
}
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
if (priv->clks[clk])
clk_disable_unprepare(priv->clks[clk]);
}
static struct hc_driver __read_mostly ehci_ctc_hc_driver;
static const struct ehci_driver_overrides platform_overrides __initconst = {
.reset = ehci_ctc_reset,
.extra_priv_size = sizeof(struct ehci_ctc_priv),
};
static struct usb_ehci_pdata ehci_ctc_defaults = {
.caps_offset = 0x100,
.dma_mask_64 = 1,
.power_on = ehci_ctc_power_on,
.power_suspend = ehci_ctc_power_off,
.power_off = ehci_ctc_power_off,
};
#define KERN_CTC KERN_ERR
static int ehci_ctc_probe(struct platform_device *dev)
{
struct usb_hcd *hcd;
struct resource *res_mem;
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_ctc_priv *priv;
struct ehci_hcd *ehci;
int err, irq, phy_num, clk = 0, rst;
if (usb_disabled())
return -ENODEV;
/*
* Use reasonable defaults so platforms don't have to provide these
* with DT probing on ARM.
*/
if (!pdata)
pdata = &ehci_ctc_defaults;
err = dma_coerce_mask_and_coherent(&dev->dev,
pdata->dma_mask_64 ?
DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
if (err) {
dev_err(&dev->dev, "Error: DMA mask configuration failed\n");
return err;
}
irq = platform_get_irq(dev, 0);
if (irq < 0) {
dev_err(&dev->dev, "no irq provided");
return irq;
}
hcd = usb_create_hcd(&ehci_ctc_hc_driver, &dev->dev,
dev_name(&dev->dev));
if (!hcd)
return -ENOMEM;
platform_set_drvdata(dev, hcd);
dev->dev.platform_data = pdata;
priv = hcd_to_ehci_priv(hcd);
ehci = hcd_to_ehci(hcd);
if (pdata == &ehci_ctc_defaults && dev->dev.of_node) {
if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
ehci->big_endian_mmio = 1;
if (of_property_read_bool(dev->dev.of_node, "big-endian-desc"))
ehci->big_endian_desc = 1;
if (of_property_read_bool(dev->dev.of_node, "big-endian"))
ehci->big_endian_mmio = ehci->big_endian_desc = 1;
if (of_property_read_bool(dev->dev.of_node,
"needs-reset-on-resume"))
priv->reset_on_resume = true;
if (of_property_read_bool(dev->dev.of_node,
"has-transaction-translator"))
hcd->has_tt = 1;
priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
"phys",
"#phy-cells");
if (priv->num_phys > 0) {
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
sizeof(struct phy *),
GFP_KERNEL);
if (!priv->phys)
return -ENOMEM;
} else
priv->num_phys = 0;
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
priv->phys[phy_num] =
devm_of_phy_get_by_index(&dev->dev,
dev->dev.of_node, phy_num);
if (IS_ERR(priv->phys[phy_num])) {
err = PTR_ERR(priv->phys[phy_num]);
goto err_put_hcd;
}
}
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
if (IS_ERR(priv->clks[clk])) {
err = PTR_ERR(priv->clks[clk]);
if (err == -EPROBE_DEFER)
goto err_put_clks;
priv->clks[clk] = NULL;
break;
}
}
}
for (rst = 0; rst < EHCI_MAX_RSTS; rst++) {
priv->rsts[rst] =
devm_reset_control_get_shared_by_index(&dev->dev, rst);
if (IS_ERR(priv->rsts[rst])) {
err = PTR_ERR(priv->rsts[rst]);
if (err == -EPROBE_DEFER)
goto err_reset;
priv->rsts[rst] = NULL;
break;
}
err = reset_control_deassert(priv->rsts[rst]);
if (err)
goto err_reset;
}
if (pdata->big_endian_desc)
ehci->big_endian_desc = 1;
if (pdata->big_endian_mmio)
ehci->big_endian_mmio = 1;
if (pdata->has_tt)
hcd->has_tt = 1;
if (pdata->reset_on_resume)
priv->reset_on_resume = true;
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
if (ehci->big_endian_mmio) {
dev_err(&dev->dev,
"Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n");
err = -EINVAL;
goto err_reset;
}
#endif
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
if (ehci->big_endian_desc) {
dev_err(&dev->dev,
"Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n");
err = -EINVAL;
goto err_reset;
}
#endif
if (pdata->power_on) {
err = pdata->power_on(dev);
if (err < 0)
goto err_reset;
}
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
if (IS_ERR(hcd->regs)) {
err = PTR_ERR(hcd->regs);
goto err_power;
}
hcd->rsrc_start = res_mem->start;
hcd->rsrc_len = resource_size(res_mem);
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (err)
goto err_power;
device_wakeup_enable(hcd->self.controller);
platform_set_drvdata(dev, hcd);
return err;
err_power:
if (pdata->power_off)
pdata->power_off(dev);
err_reset:
while (--rst >= 0)
reset_control_assert(priv->rsts[rst]);
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
err_put_hcd:
if (pdata == &ehci_ctc_defaults)
dev->dev.platform_data = NULL;
usb_put_hcd(hcd);
return err;
}
static int ehci_ctc_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
int clk, rst;
usb_remove_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++)
reset_control_assert(priv->rsts[rst]);
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
clk_put(priv->clks[clk]);
usb_put_hcd(hcd);
if (pdata == &ehci_ctc_defaults)
dev->dev.platform_data = NULL;
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int ehci_ctc_suspend(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
bool do_wakeup = device_may_wakeup(dev);
int ret;
ret = ehci_suspend(hcd, do_wakeup);
if (ret)
return ret;
if (pdata->power_suspend)
pdata->power_suspend(pdev);
return ret;
}
static int ehci_ctc_resume(struct device *dev)
{
struct usb_hcd *hcd = dev_get_drvdata(dev);
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
struct platform_device *pdev = to_platform_device(dev);
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
if (pdata->power_on) {
int err = pdata->power_on(pdev);
if (err < 0)
return err;
}
ehci_resume(hcd, priv->reset_on_resume);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static const struct of_device_id ctc_ehci_ids[] = {
{.compatible = "ctc-ehci",},
{}
};
MODULE_DEVICE_TABLE(of, ctc_ehci_ids);
static const struct platform_device_id ehci_ctc_table[] = {
{"ehci-ctc", 0},
{}
};
MODULE_DEVICE_TABLE(platform, ehci_ctc_table);
static SIMPLE_DEV_PM_OPS(ehci_ctc_pm_ops, ehci_ctc_suspend, ehci_ctc_resume);
static struct platform_driver ehci_ctc_driver = {
.id_table = ehci_ctc_table,
.probe = ehci_ctc_probe,
.remove = ehci_ctc_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ehci-ctc",
.pm = &ehci_ctc_pm_ops,
.of_match_table = ctc_ehci_ids,
}
};
static int __init ehci_ctc_init(void)
{
if (usb_disabled())
return -ENODEV;
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
ehci_init_driver(&ehci_ctc_hc_driver, &platform_overrides);
return platform_driver_register(&ehci_ctc_driver);
}
module_init(ehci_ctc_init);
static void __exit ehci_ctc_cleanup(void)
{
platform_driver_unregister(&ehci_ctc_driver);
}
module_exit(ehci_ctc_cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Hauke Mehrtens");
MODULE_AUTHOR("Alan Stern");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,894 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2001-2002 by David Brownell
*/
#ifndef __LINUX_EHCI_HCD_H
#define __LINUX_EHCI_HCD_H
/* definitions used for the EHCI driver */
/*
* __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
* __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
* the host controller implementation.
*
* To facilitate the strongest possible byte-order checking from "sparse"
* and so on, we use __leXX unless that's not practical.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
typedef __u32 __bitwise __hc32;
typedef __u16 __bitwise __hc16;
#else
#define __hc32 __le32
#define __hc16 __le16
#endif
/* statistics can be kept for tuning/monitoring */
#ifdef CONFIG_DYNAMIC_DEBUG
#define EHCI_STATS
#endif
struct ehci_stats {
/* irq usage */
unsigned long normal;
unsigned long error;
unsigned long iaa;
unsigned long lost_iaa;
/* termination of urbs from core */
unsigned long complete;
unsigned long unlink;
};
/*
* Scheduling and budgeting information for periodic transfers, for both
* high-speed devices and full/low-speed devices lying behind a TT.
*/
struct ehci_per_sched {
struct usb_device *udev; /* access to the TT */
struct usb_host_endpoint *ep;
struct list_head ps_list; /* node on ehci_tt's ps_list */
u16 tt_usecs; /* time on the FS/LS bus */
u16 cs_mask; /* C-mask and S-mask bytes */
u16 period; /* actual period in frames */
u16 phase; /* actual phase, frame part */
u8 bw_phase; /* same, for bandwidth
reservation */
u8 phase_uf; /* uframe part of the phase */
u8 usecs, c_usecs; /* times on the HS bus */
u8 bw_uperiod; /* period in microframes, for
bandwidth reservation */
u8 bw_period; /* same, in frames */
};
#define NO_FRAME 29999 /* frame not assigned yet */
/* ehci_hcd->lock guards shared data against other CPUs:
* ehci_hcd: async, unlink, periodic (and shadow), ...
* usb_host_endpoint: hcpriv
* ehci_qh: qh_next, qtd_list
* ehci_qtd: qtd_list
*
* Also, hold this lock when talking to HC registers or
* when updating hw_* fields in shared qh/qtd/... structures.
*/
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
/*
* ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
* controller may be doing DMA. Lower values mean there's no DMA.
*/
enum ehci_rh_state {
EHCI_RH_HALTED,
EHCI_RH_SUSPENDED,
EHCI_RH_RUNNING,
EHCI_RH_STOPPING
};
/*
* Timer events, ordered by increasing delay length.
* Always update event_delays_ns[] and event_handlers[] (defined in
* ehci-timer.c) in parallel with this list.
*/
enum ehci_hrtimer_event {
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
EHCI_HRTIMER_ACTIVE_UNLINK, /* Wait while unlinking an active QH */
EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
};
#define EHCI_HRTIMER_NO_EVENT 99
struct ehci_hcd { /* one per controller */
/* timing support */
enum ehci_hrtimer_event next_hrtimer_event;
unsigned enabled_hrtimer_events;
ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
struct hrtimer hrtimer;
int PSS_poll_count;
int ASS_poll_count;
int died_poll_count;
/* glue to PCI and HCD framework */
struct ehci_caps __iomem *caps;
struct ehci_regs __iomem *regs;
struct ehci_dbg_port __iomem *debug;
__u32 hcs_params; /* cached register copy */
spinlock_t lock;
enum ehci_rh_state rh_state;
/* general schedule support */
bool scanning:1;
bool need_rescan:1;
bool intr_unlinking:1;
bool iaa_in_progress:1;
bool async_unlinking:1;
bool shutdown:1;
struct ehci_qh *qh_scan_next;
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *dummy; /* For AMD quirk use */
struct list_head async_unlink;
struct list_head async_idle;
unsigned async_unlink_cycle;
unsigned async_count; /* async activity count */
__hc32 old_current; /* Test for QH becoming */
__hc32 old_token; /* inactive during unlink */
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
unsigned periodic_size;
__hc32 *periodic; /* hw periodic table */
dma_addr_t periodic_dma;
struct list_head intr_qh_list;
unsigned i_thresh; /* uframes HC might cache */
union ehci_shadow *pshadow; /* mirror hw periodic table */
struct list_head intr_unlink_wait;
struct list_head intr_unlink;
unsigned intr_unlink_wait_cycle;
unsigned intr_unlink_cycle;
unsigned now_frame; /* frame from HC hardware */
unsigned last_iso_frame; /* last frame scanned for iso */
unsigned intr_count; /* intr activity count */
unsigned isoc_count; /* isoc activity count */
unsigned periodic_count; /* periodic activity count */
unsigned uframe_periodic_max; /* max periodic time per uframe */
/* list of itds & sitds completed while now_frame was still active */
struct list_head cached_itd_list;
struct ehci_itd *last_itd_to_free;
struct list_head cached_sitd_list;
struct ehci_sitd *last_sitd_to_free;
/* per root hub port */
unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
/* bit vectors (one bit per port) */
unsigned long bus_suspended; /* which ports were
already suspended at the start of a bus suspend */
unsigned long companion_ports; /* which ports are
dedicated to the companion controller */
unsigned long owned_ports; /* which ports are
owned by the companion during a bus suspend */
unsigned long port_c_suspend; /* which ports have
the change-suspend feature turned on */
unsigned long suspended_ports; /* which ports are
suspended */
unsigned long resuming_ports; /* which ports have
started to resume */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
struct dma_pool *qtd_pool; /* one or more per qh */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
unsigned random_frame;
unsigned long next_statechange;
ktime_t last_periodic_enable;
u32 command;
/* SILICON QUIRKS */
unsigned no_selective_suspend:1;
unsigned has_fsl_port_bug:1; /* FreeScale */
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
unsigned big_endian_mmio:1;
unsigned big_endian_desc:1;
unsigned big_endian_capbase:1;
unsigned has_amcc_usb23:1;
unsigned need_io_watchdog:1;
unsigned amd_pll_fix:1;
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
/* required for usb32 quirk */
#define OHCI_CTRL_HCFS (3 << 6)
#define OHCI_USB_OPER (2 << 6)
#define OHCI_USB_SUSPEND (3 << 6)
#define OHCI_HCCTRL_OFFSET 0x4
#define OHCI_HCCTRL_LEN 0x4
__hc32 *ohci_hcctrl_reg;
unsigned has_hostpc:1;
unsigned has_tdi_phy_lpm:1;
unsigned has_ppcd:1; /* support per-port change bits */
u8 sbrn; /* packed release number */
/* irq statistics */
#ifdef EHCI_STATS
struct ehci_stats stats;
# define COUNT(x) ((x)++)
#else
# define COUNT(x)
#endif
/* debug files */
#ifdef CONFIG_DYNAMIC_DEBUG
struct dentry *debug_dir;
#endif
/* bandwidth usage */
#define EHCI_BANDWIDTH_SIZE 64
#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3)
u8 bandwidth[EHCI_BANDWIDTH_SIZE];
/* us allocated per uframe */
u8 tt_budget[EHCI_BANDWIDTH_SIZE];
/* us budgeted per uframe */
struct list_head tt_list;
/* platform-specific data -- must come last */
unsigned long priv[0] __aligned(sizeof(s64));
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
static inline struct ehci_hcd *hcd_to_ehci(struct usb_hcd *hcd)
{
return (struct ehci_hcd *) (hcd->hcd_priv);
}
static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
{
return container_of((void *) ehci, struct usb_hcd, hcd_priv);
}
/*-------------------------------------------------------------------------*/
#include <linux/usb/ehci_def.h>
/*-------------------------------------------------------------------------*/
#define QTD_NEXT(ehci, dma) cpu_to_hc32(ehci, (u32)dma)
/*
* EHCI Specification 0.95 Section 3.5
* QTD: describe data transfer components (buffer, direction, ...)
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
*
* These are associated only with "QH" (Queue Head) structures,
* used with control, bulk, and interrupt transfers.
*/
struct ehci_qtd {
/* first part defined by EHCI spec */
__hc32 hw_next; /* see EHCI 3.5.1 */
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
__hc32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
#define QTD_CERR(tok) (((tok)>>10) & 0x3)
#define QTD_PID(tok) (((tok)>>8) & 0x3)
#define QTD_STS_ACTIVE (1 << 7) /* HC may execute this */
#define QTD_STS_HALT (1 << 6) /* halted on error */
#define QTD_STS_DBE (1 << 5) /* data buffer error (in HC) */
#define QTD_STS_BABBLE (1 << 4) /* device was babbling (qtd halted) */
#define QTD_STS_XACT (1 << 3) /* device gave illegal response */
#define QTD_STS_MMF (1 << 2) /* incomplete split transaction */
#define QTD_STS_STS (1 << 1) /* split transaction state */
#define QTD_STS_PING (1 << 0) /* issue PING? */
#define ACTIVE_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_ACTIVE)
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
__hc32 hw_buf[5]; /* see EHCI 3.5.4 */
__hc32 hw_buf_hi[5]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t qtd_dma; /* qtd address */
struct list_head qtd_list; /* sw qtd list */
struct urb *urb; /* qtd's urb */
size_t length; /* length of buffer */
} __aligned(32);
/* mask NakCnt+T in qh->hw_alt_next */
#define QTD_MASK(ehci) cpu_to_hc32(ehci, ~0x1f)
#define IS_SHORT_READ(token) (QTD_LENGTH(token) != 0 && QTD_PID(token) == 1)
/*-------------------------------------------------------------------------*/
/* type tag from {qh,itd,sitd,fstn}->hw_next */
#define Q_NEXT_TYPE(ehci, dma) ((dma) & cpu_to_hc32(ehci, 3 << 1))
/*
* Now the following defines are not converted using the
* cpu_to_le32() macro anymore, since we have to support
* "dynamic" switching between be and le support, so that the driver
* can be used on one system with SoC EHCI controller using big-endian
* descriptors as well as a normal little-endian PCI EHCI controller.
*/
/* values for that type tag */
#define Q_TYPE_ITD (0 << 1)
#define Q_TYPE_QH (1 << 1)
#define Q_TYPE_SITD (2 << 1)
#define Q_TYPE_FSTN (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(ehci, dma) \
(cpu_to_hc32(ehci, (((u32) dma) & ~0x01f) | Q_TYPE_QH))
/* for periodic/async schedules and qtd lists, mark end of list */
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
/*
* Entries in periodic shadow table are pointers to one of four kinds
* of data structure. That's dictated by the hardware; a type tag is
* encoded in the low bits of the hardware's periodic schedule. Use
* Q_NEXT_TYPE to get the tag.
*
* For entries in the async schedule, the type tag always says "qh".
*/
union ehci_shadow {
struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
__hc32 *hw_next; /* (all types) */
void *ptr;
};
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.95 Section 3.6
* QH: describes control/bulk/interrupt endpoints
* See Fig 3-7 "Queue Head Structure Layout".
*
* These appear in both the async and (for interrupt) periodic schedules.
*/
/* first part defined by EHCI spec */
struct ehci_qh_hw {
__hc32 hw_next; /* see EHCI 3.6.1 */
__hc32 hw_info1; /* see EHCI 3.6.2 */
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
#define QH_HIGH_SPEED (2 << 12) /* Endpoint speed */
#define QH_LOW_SPEED (1 << 12)
#define QH_FULL_SPEED (0 << 12)
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
__hc32 hw_info2; /* see EHCI 3.6.2 */
#define QH_SMASK 0x000000ff
#define QH_CMASK 0x0000ff00
#define QH_HUBADDR 0x007f0000
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__hc32 hw_qtd_next;
__hc32 hw_alt_next;
__hc32 hw_token;
__hc32 hw_buf[5];
__hc32 hw_buf_hi[5];
} __aligned(32);
struct ehci_qh {
struct ehci_qh_hw *hw; /* Must come first */
/* the rest is HCD-private */
dma_addr_t qh_dma; /* address of qh */
union ehci_shadow qh_next; /* ptr to qh; or periodic */
struct list_head qtd_list; /* sw qtd list */
struct list_head intr_node; /* list of intr QHs */
struct ehci_qtd *dummy;
struct list_head unlink_node;
struct ehci_per_sched ps; /* scheduling info */
unsigned unlink_cycle;
u8 qh_state;
#define QH_STATE_LINKED 1 /* HC sees this */
#define QH_STATE_UNLINK 2 /* HC may still see this */
#define QH_STATE_IDLE 3 /* HC doesn't see this */
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
u8 xacterrs; /* XactErr retry counter */
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
u8 unlink_reason;
#define QH_UNLINK_HALTED 0x01 /* Halt flag is set */
#define QH_UNLINK_SHORT_READ 0x02 /* Recover from a short read */
#define QH_UNLINK_DUMMY_OVERLAY 0x04 /* QH overlayed the dummy TD */
#define QH_UNLINK_SHUTDOWN 0x08 /* The HC isn't running */
#define QH_UNLINK_QUEUE_EMPTY 0x10 /* Reached end of the queue */
#define QH_UNLINK_REQUESTED 0x20 /* Disable, reset, or dequeue */
u8 gap_uf; /* uframes split/csplit gap */
unsigned is_out:1; /* bulk or intr OUT */
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
unsigned dequeue_during_giveback:1;
unsigned should_be_inactive:1;
};
/*-------------------------------------------------------------------------*/
/* description of one iso transaction (up to 3 KB data if highspeed) */
struct ehci_iso_packet {
/* These will be copied to iTD when scheduling */
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
__hc32 transaction; /* itd->hw_transaction[i] |= */
u8 cross; /* buf crosses pages */
/* for full speed OUT splits */
u32 buf1;
};
/* temporary schedule data for packets from iso urbs (both speeds)
* each packet is one logical usb transaction to the device (not TT),
* beginning at stream->next_uframe
*/
struct ehci_iso_sched {
struct list_head td_list;
unsigned span;
unsigned first_packet;
struct ehci_iso_packet packet[0];
};
/*
* ehci_iso_stream - groups all (s)itds for this endpoint.
* acts like a qh would, if EHCI had them for ISO.
*/
struct ehci_iso_stream {
/* first field matches ehci_hq, but is NULL */
struct ehci_qh_hw *hw;
u8 bEndpointAddress;
u8 highspeed;
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
/* output of (re)scheduling */
struct ehci_per_sched ps; /* scheduling info */
unsigned next_uframe;
__hc32 splits;
/* the rest is derived from the endpoint descriptor,
* including the extra info for hw_bufp[0..2]
*/
u16 uperiod; /* period in uframes */
u16 maxp;
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
__hc32 buf0;
__hc32 buf1;
__hc32 buf2;
/* this is used to initialize sITD's tt info */
__hc32 address;
};
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.95 Section 3.3
* Fig 3-4 "Isochronous Transaction Descriptor (iTD)"
*
* Schedule records for high speed iso xfers
*/
struct ehci_itd {
/* first part defined by EHCI spec */
__hc32 hw_next; /* see EHCI 3.3.1 */
__hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
__hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
__hc32 hw_bufp_hi[7]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t itd_dma; /* for this itd */
union ehci_shadow itd_next; /* ptr to periodic q entry */
struct urb *urb;
struct ehci_iso_stream *stream; /* endpoint's queue */
struct list_head itd_list; /* list of stream's itds */
/* any/all hw_transactions here may be used by that urb */
unsigned frame; /* where scheduled */
unsigned pg;
unsigned index[8]; /* in urb->iso_frame_desc */
} __aligned(32);
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.95 Section 3.4
* siTD, aka split-transaction isochronous Transfer Descriptor
* ... describe full speed iso xfers through TT in hubs
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
*/
struct ehci_sitd {
/* first part defined by EHCI spec */
__hc32 hw_next;
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
__hc32 hw_uframe; /* EHCI table 3-10 */
__hc32 hw_results; /* EHCI table 3-11 */
#define SITD_IOC (1 << 31) /* interrupt on completion */
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
#define SITD_LENGTH(x) (((x) >> 16) & 0x3ff)
#define SITD_STS_ACTIVE (1 << 7) /* HC may execute this */
#define SITD_STS_ERR (1 << 6) /* error from TT */
#define SITD_STS_DBE (1 << 5) /* data buffer error (in HC) */
#define SITD_STS_BABBLE (1 << 4) /* device was babbling */
#define SITD_STS_XACT (1 << 3) /* illegal IN response */
#define SITD_STS_MMF (1 << 2) /* incomplete split transaction */
#define SITD_STS_STS (1 << 1) /* split transaction state */
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
__hc32 hw_buf[2]; /* EHCI table 3-12 */
__hc32 hw_backpointer; /* EHCI table 3-13 */
__hc32 hw_buf_hi[2]; /* Appendix B */
/* the rest is HCD-private */
dma_addr_t sitd_dma;
union ehci_shadow sitd_next; /* ptr to periodic q entry */
struct urb *urb;
struct ehci_iso_stream *stream; /* endpoint's queue */
struct list_head sitd_list; /* list of stream's sitds */
unsigned frame;
unsigned index;
} __aligned(32);
/*-------------------------------------------------------------------------*/
/*
* EHCI Specification 0.96 Section 3.7
* Periodic Frame Span Traversal Node (FSTN)
*
* Manages split interrupt transactions (using TT) that span frame boundaries
* into uframes 0/1; see 4.12.2.2. In those uframes, a "save place" FSTN
* makes the HC jump (back) to a QH to scan for fs/ls QH completions until
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
*/
struct ehci_fstn {
__hc32 hw_next; /* any periodic q entry */
__hc32 hw_prev; /* qh or EHCI_LIST_END */
/* the rest is HCD-private */
dma_addr_t fstn_dma;
union ehci_shadow fstn_next; /* ptr to periodic q entry */
} __aligned(32);
/*-------------------------------------------------------------------------*/
/*
* USB-2.0 Specification Sections 11.14 and 11.18
* Scheduling and budgeting split transactions using TTs
*
* A hub can have a single TT for all its ports, or multiple TTs (one for each
* port). The bandwidth and budgeting information for the full/low-speed bus
* below each TT is self-contained and independent of the other TTs or the
* high-speed bus.
*
* "Bandwidth" refers to the number of microseconds on the FS/LS bus allocated
* to an interrupt or isochronous endpoint for each frame. "Budget" refers to
* the best-case estimate of the number of full-speed bytes allocated to an
* endpoint for each microframe within an allocated frame.
*
* Removal of an endpoint invalidates a TT's budget. Instead of trying to
* keep an up-to-date record, we recompute the budget when it is needed.
*/
struct ehci_tt {
u16 bandwidth[EHCI_BANDWIDTH_FRAMES];
struct list_head tt_list; /* List of all ehci_tt's */
struct list_head ps_list; /* Items using this TT */
struct usb_tt *usb_tt;
int tt_port; /* TT port number */
};
/*-------------------------------------------------------------------------*/
/* Prepare the PORTSC wakeup flags during controller suspend/resume */
#define ehci_prepare_ports_for_controller_suspend(ehci, do_wakeup) \
ehci_adjust_port_wakeup_flags(ehci, true, do_wakeup)
#define ehci_prepare_ports_for_controller_resume(ehci) \
ehci_adjust_port_wakeup_flags(ehci, false, false)
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_USB_EHCI_ROOT_HUB_TT
/*
* Some EHCI controllers have a Transaction Translator built into the
* root hub. This is a non-standard feature. Each controller will need
* to add code to the following inline functions, and call them as
* needed (mostly in root hub code).
*/
#define ehci_is_TDI(e) (ehci_to_hcd(e)->has_tt)
/* Returns the speed of a device attached to a port on the root hub. */
static inline unsigned int
ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
{
if (ehci_is_TDI(ehci)) {
switch ((portsc >> (ehci->has_hostpc ? 25 : 26)) & 3) {
case 0:
return 0;
case 1:
return USB_PORT_STAT_LOW_SPEED;
case 2:
default:
return USB_PORT_STAT_HIGH_SPEED;
}
}
return USB_PORT_STAT_HIGH_SPEED;
}
#else
#define ehci_is_TDI(e) (0)
#define ehci_port_speed(ehci, portsc) USB_PORT_STAT_HIGH_SPEED
#endif
/*-------------------------------------------------------------------------*/
#ifdef CONFIG_PPC_83xx
/* Some Freescale processors have an erratum in which the TT
* port number in the queue head was 0..N-1 instead of 1..N.
*/
#define ehci_has_fsl_portno_bug(e) ((e)->has_fsl_port_bug)
#else
#define ehci_has_fsl_portno_bug(e) (0)
#endif
#define PORTSC_FSL_PFSC 24 /* Port Force Full-Speed Connect */
#if defined(CONFIG_PPC_85xx)
/* Some Freescale processors have an erratum (USB A-005275) in which
* incoming packets get corrupted in HS mode
*/
#define ehci_has_fsl_hs_errata(e) ((e)->has_fsl_hs_errata)
#else
#define ehci_has_fsl_hs_errata(e) (0)
#endif
/*
* Some Freescale/NXP processors have an erratum (USB A-005697)
* in which we need to wait for 10ms for bus to enter suspend mode
* after setting SUSP bit.
*/
#define ehci_has_fsl_susp_errata(e) ((e)->has_fsl_susp_errata)
/*
* While most USB host controllers implement their registers in
* little-endian format, a minority (celleb companion chip) implement
* them in big endian format.
*
* This attempts to support either format at compile time without a
* runtime penalty, or both formats with the additional overhead
* of checking a flag bit.
*
* ehci_big_endian_capbase is a special quirk for controllers that
* implement the HC capability registers as separate registers and not
* as fields of a 32-bit register.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
#define ehci_big_endian_capbase(e) ((e)->big_endian_capbase)
#else
#define ehci_big_endian_mmio(e) 0
#define ehci_big_endian_capbase(e) 0
#endif
/*
* Big-endian read/write functions are arch-specific.
* Other arches can be added if/when they're needed.
*/
#if defined(CONFIG_ARM) && defined(CONFIG_ARCH_IXP4XX)
#define readl_be(addr) __raw_readl((__force unsigned *)addr)
#define writel_be(val, addr) __raw_writel(val, (__force unsigned *)addr)
#endif
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
__u32 __iomem *regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
return ehci_big_endian_mmio(ehci) ?
readl_be(regs) :
readl(regs);
#else
return readl(regs);
#endif
}
#ifdef CONFIG_SOC_IMX28
static inline void imx28_ehci_writel(const unsigned int val,
volatile __u32 __iomem *addr)
{
__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr));
}
#else
static inline void imx28_ehci_writel(const unsigned int val,
volatile __u32 __iomem *addr)
{
}
#endif
static inline void ehci_writel(const struct ehci_hcd *ehci,
const unsigned int val, __u32 __iomem *regs)
{
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
ehci_big_endian_mmio(ehci) ?
writel_be(val, regs) :
writel(val, regs);
#else
if (ehci->imx28_write_fix)
imx28_ehci_writel(val, regs);
else
writel(val, regs);
#endif
}
/*
* On certain ppc-44x SoC there is a HW issue, that could only worked around with
* explicit suspend/operate of OHCI. This function hereby makes sense only on that arch.
* Other common bits are dependent on has_amcc_usb23 quirk flag.
*/
#ifdef CONFIG_44x
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
{
u32 hc_control;
hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS);
if (operational)
hc_control |= OHCI_USB_OPER;
else
hc_control |= OHCI_USB_SUSPEND;
writel_be(hc_control, ehci->ohci_hcctrl_reg);
(void) readl_be(ehci->ohci_hcctrl_reg);
}
#else
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
{ }
#endif
/*-------------------------------------------------------------------------*/
/*
* The AMCC 440EPx not only implements its EHCI registers in big-endian
* format, but also its DMA data structures (descriptors).
*
* EHCI controllers accessed through PCI work normally (little-endian
* everywhere), so we won't bother supporting a BE-only mode for now.
*/
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
#define ehci_big_endian_desc(e) ((e)->big_endian_desc)
/* cpu to ehci */
static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
{
return ehci_big_endian_desc(ehci)
? (__force __hc32)cpu_to_be32(x)
: (__force __hc32)cpu_to_le32(x);
}
/* ehci to cpu */
static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpu((__force __be32)x)
: le32_to_cpu((__force __le32)x);
}
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
{
return ehci_big_endian_desc(ehci)
? be32_to_cpup((__force __be32 *)x)
: le32_to_cpup((__force __le32 *)x);
}
#else
/* cpu to ehci */
static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
{
return cpu_to_le32(x);
}
/* ehci to cpu */
static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
{
return le32_to_cpu(x);
}
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
{
return le32_to_cpup(x);
}
#endif
/*-------------------------------------------------------------------------*/
#define ehci_dbg(ehci, fmt, args...) \
dev_dbg(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_err(ehci, fmt, args...) \
dev_err(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_info(ehci, fmt, args...) \
dev_info(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
#define ehci_warn(ehci, fmt, args...) \
dev_warn(ehci_to_hcd(ehci)->self.controller, fmt, ## args)
/*-------------------------------------------------------------------------*/
/* Declarations of things exported for use by ehci platform drivers */
struct ehci_driver_overrides {
size_t extra_priv_size;
int (*reset)(struct usb_hcd *hcd);
int (*port_power)(struct usb_hcd *hcd,
int portnum, bool enable);
};
extern void ehci_init_driver(struct hc_driver *drv,
const struct ehci_driver_overrides *over);
extern int ehci_setup(struct usb_hcd *hcd);
extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
u32 mask, u32 done, int usec);
extern int ehci_reset(struct ehci_hcd *ehci);
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
extern void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
bool suspending, bool do_wakeup);
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength);
#endif /* __LINUX_EHCI_HCD_H */

View File

@ -0,0 +1 @@
obj-m = gpio-ctc.o

Some files were not shown because too many files have changed in this diff Show More