meta-ampere: mtmitchell: support automatic FAN control

Implement automatic FAN control table provided by ODM.
The FAN console service will set Fans to 100% duty cycle in below cases:
- Lacking any of the fans
- Any of the fan tachs is non-functional (not running at the desired
  target)
- Any of the controlling sensors is non-functional (except for pluggable
  device sensors)

Change-Id: Id7069e0731cb330a9d39c9334d4d20ad4179e9e5
Signed-off-by: Chau Ly <chaul@amperecomputing.com>
diff --git a/meta-ampere/meta-common/recipes-phosphor/fans/phosphor-fan_%.bbappend b/meta-ampere/meta-common/recipes-phosphor/fans/phosphor-fan_%.bbappend
index 5a3a678..524b5f8 100644
--- a/meta-ampere/meta-common/recipes-phosphor/fans/phosphor-fan_%.bbappend
+++ b/meta-ampere/meta-common/recipes-phosphor/fans/phosphor-fan_%.bbappend
@@ -4,5 +4,5 @@
 # To use CurrentHostState to decide host state for phosphor-fan-monitor
 
 PACKAGECONFIG:append = " delay-host-control monitor-use-host-state"
-PACKAGECONFIG[delay-host-control] = "-Ddelay-host-control=20"
+PACKAGECONFIG[delay-host-control] = "-Ddelay-host-control=150"
 PACKAGECONFIG[monitor-use-host-state] = "-Dmonitor-use-host-state=enabled"
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/events.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/events.json
new file mode 100644
index 0000000..1a27aa0
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/events.json
@@ -0,0 +1,718 @@
+[
+  {
+    // Hold fans at the given target when a number of fans are missing.
+    "name": "fan(s) missing",
+    "groups": [
+      {
+        "name": "fan inventory",
+        "interface": "xyz.openbmc_project.Inventory.Item",
+        "property": { "name": "Present" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "signal",
+        "signal": "interfaces_added"
+      }
+    ],
+    "actions": [
+      {
+        "name": "count_state_before_target",
+        "count": 1,
+        "state": false,
+        "target": 255
+      }
+    ]
+  },
+  {
+    // Hold fans at the given target when a number of rotors are nonfunctional.
+    "name": "fan rotor(s) faulted",
+    "groups": [
+      {
+        "name": "fan0 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "fan1 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "fan2 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "fan3 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "fan4 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "fan5 rotor inventory",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "signal",
+        "signal": "interfaces_added"
+      }
+    ],
+    "actions": [
+      {
+        "name": "count_state_before_target",
+        "count": 1,
+        "state": false,
+        "target": 255
+      }
+    ]
+  },
+  {
+    // Set a raised fan floor when any PLDM temperature sensor is nonfunctional
+    "name": "Nonfunctional PLDM sensors",
+    "groups": [
+      {
+        "name": "PLDM Sensors",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "signal",
+        "signal": "interfaces_added"
+      }
+    ],
+    "actions": [
+      {
+        "name": "count_state_before_target",
+        "groups": [
+          {
+            "name": "PLDM Sensors",
+            "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            "property": { "name": "Functional" }
+          }
+        ],
+        "count": 1,
+        "state": false,
+        "target": 255
+      }
+    ]
+  },
+  {
+    // Set a raised fan floor when any temperature sensor is nonfunctional
+    "name": "Nonfunctional temperature sensors",
+    "groups": [
+      {
+        "name": "Sys Inlet Temp Components",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "CPU Temps",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "PSU Max Temps",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      },
+      {
+        "name": "PCIE Zone Temps",
+        "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+        "property": { "name": "Functional" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 6000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "count_state_before_target",
+        "groups": [
+          {
+            "name": "Sys Inlet Temp Components",
+            "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            "property": { "name": "Functional" }
+          },
+          {
+            "name": "CPU Temps",
+            "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            "property": { "name": "Functional" }
+          },
+          {
+            "name": "PSU Max Temps",
+            "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            "property": { "name": "Functional" }
+          },
+          {
+            "name": "PCIE Zone Temps",
+            "interface": "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            "property": { "name": "Functional" }
+          }
+        ],
+        "count": 10,
+        "state": false,
+        "target": 255
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from CPU Temps",
+    "groups": [
+      {
+        "name": "CPU Temps",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "CPU Temps",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 77.0 },
+                { "value": 50.0, "target": 89.0 },
+                { "value": 60.0, "target": 102.0 },
+                { "value": 65.0, "target": 115.0 },
+                { "value": 70.0, "target": 122.0 },
+                { "value": 76.0, "target": 128.0 },
+                { "value": 77.0, "target": 130.0 },
+                { "value": 78.0, "target": 133.0 },
+                { "value": 79.0, "target": 135.0 },
+                { "value": 80.0, "target": 138.0 },
+                { "value": 81.0, "target": 140.0 },
+                { "value": 82.0, "target": 143.0 },
+                { "value": 83.0, "target": 145.0 },
+                { "value": 84.0, "target": 148.0 },
+                { "value": 85.0, "target": 161.0 },
+                { "value": 86.0, "target": 173.0 },
+                { "value": 87.0, "target": 181.0 },
+                { "value": 88.0, "target": 189.0 },
+                { "value": 89.0, "target": 196.0 },
+                { "value": 90.0, "target": 204.0 },
+                { "value": 91.0, "target": 207.0 },
+                { "value": 92.0, "target": 232.0 },
+                { "value": 93.0, "target": 237.0 },
+                { "value": 94.0, "target": 242.0 },
+                { "value": 95.0, "target": 247.0 },
+                { "value": 96.0, "target": 252.0 },
+                { "value": 97.0, "target": 255.0 },
+                { "value": 98.0, "target": 255.0 },
+                { "value": 99.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from CPU DIMM Temps",
+    "groups": [
+      {
+        "name": "CPU DIMM Temps",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "CPU DIMM Temps",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 20.0, "target": 51.0 },
+                { "value": 30.0, "target": 64.0 },
+                { "value": 35.0, "target": 77.0 },
+                { "value": 38.0, "target": 89.0 },
+                { "value": 40.0, "target": 102.0 },
+                { "value": 45.0, "target": 115.0 },
+                { "value": 50.0, "target": 128.0 },
+                { "value": 54.0, "target": 140.0 },
+                { "value": 58.0, "target": 153.0 },
+                { "value": 63.0, "target": 166.0 },
+                { "value": 67.0, "target": 179.0 },
+                { "value": 70.0, "target": 191.0 },
+                { "value": 73.0, "target": 204.0 },
+                { "value": 75.0, "target": 230.0 },
+                { "value": 80.0, "target": 242.0 },
+                { "value": 85.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from NVMeM2 Max Temp",
+    "groups": [
+      {
+        "name": "NVMeM2 Max Temp",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "NVMeM2 Max Temp",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 51.0 },
+                { "value": 25.0, "target": 77.0 },
+                { "value": 30.0, "target": 82.0 },
+                { "value": 34.0, "target": 87.0 },
+                { "value": 35.0, "target": 92.0 },
+                { "value": 36.0, "target": 97.0 },
+                { "value": 37.0, "target": 102.0 },
+                { "value": 38.0, "target": 115.0 },
+                { "value": 39.0, "target": 128.0 },
+                { "value": 40.0, "target": 140.0 },
+                { "value": 41.0, "target": 153.0 },
+                { "value": 42.0, "target": 166.0 },
+                { "value": 45.0, "target": 179.0 },
+                { "value": 50.0, "target": 191.0 },
+                { "value": 55.0, "target": 204.0 },
+                { "value": 60.0, "target": 217.0 },
+                { "value": 63.0, "target": 230.0 },
+                { "value": 65.0, "target": 242.0 },
+                { "value": 70.0, "target": 245.0 },
+                { "value": 85.0, "target": 250.0 },
+                { "value": 87.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from NVMeFBP Max Temp",
+    "groups": [
+      {
+        "name": "NVMeFBP Max Temp",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "NVMeFBP Max Temp",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 10.0, "target": 38.0 },
+                { "value": 20.0, "target": 51.0 },
+                { "value": 30.0, "target": 77.0 },
+                { "value": 35.0, "target": 89.0 },
+                { "value": 38.0, "target": 102.0 },
+                { "value": 40.0, "target": 128.0 },
+                { "value": 43.0, "target": 153.0 },
+                { "value": 45.0, "target": 179.0 },
+                { "value": 47.0, "target": 204.0 },
+                { "value": 50.0, "target": 217.0 },
+                { "value": 65.0, "target": 230.0 },
+                { "value": 68.0, "target": 242.0 },
+                { "value": 70.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from OCP Max Temp",
+    "groups": [
+      {
+        "name": "OCP Max Temp",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "OCP Max Temp",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 30.0, "target": 38.0 },
+                { "value": 40.0, "target": 51.0 },
+                { "value": 45.0, "target": 64.0 },
+                { "value": 50.0, "target": 77.0 },
+                { "value": 55.0, "target": 89.0 },
+                { "value": 60.0, "target": 102.0 },
+                { "value": 64.0, "target": 115.0 },
+                { "value": 67.0, "target": 122.0 },
+                { "value": 70.0, "target": 128.0 },
+                { "value": 75.0, "target": 140.0 },
+                { "value": 77.0, "target": 145.0 },
+                { "value": 79.0, "target": 150.0 },
+                { "value": 80.0, "target": 153.0 },
+                { "value": 81.0, "target": 179.0 },
+                { "value": 82.0, "target": 184.0 },
+                { "value": 84.0, "target": 194.0 },
+                { "value": 85.0, "target": 199.0 },
+                { "value": 86.0, "target": 212.0 },
+                { "value": 87.0, "target": 224.0 },
+                { "value": 88.0, "target": 232.0 },
+                { "value": 89.0, "target": 240.0 },
+                { "value": 90.0, "target": 247.0 },
+                { "value": 100.0, "target": 255.0 },
+                { "value": 105.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from PSU Max Temps",
+    "groups": [
+      {
+        "name": "PSU Max Temps",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "PSU Max Temps",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 10.0, "target": 51.0 },
+                { "value": 20.0, "target": 77.0 },
+                { "value": 25.0, "target": 89.0 },
+                { "value": 30.0, "target": 102.0 },
+                { "value": 35.0, "target": 115.0 },
+                { "value": 38.0, "target": 128.0 },
+                { "value": 40.0, "target": 140.0 },
+                { "value": 43.0, "target": 153.0 },
+                { "value": 45.0, "target": 166.0 },
+                { "value": 47.0, "target": 179.0 },
+                { "value": 49.0, "target": 191.0 },
+                { "value": 52.0, "target": 204.0 },
+                { "value": 54.0, "target": 242.0 },
+                { "value": 55.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from PCIE Zone Temps",
+    "groups": [
+      {
+        "name": "PCIE Zone Temps",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "PCIE Zone Temps",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 25.0, "target": 38.0 },
+                { "value": 35.0, "target": 51.0 },
+                { "value": 37.0, "target": 56.0 },
+                { "value": 38.0, "target": 64.0 },
+                { "value": 40.0, "target": 77.0 },
+                { "value": 42.0, "target": 89.0 },
+                { "value": 43.0, "target": 102.0 },
+                { "value": 44.0, "target": 115.0 },
+                { "value": 45.0, "target": 128.0 },
+                { "value": 46.0, "target": 140.0 },
+                { "value": 47.0, "target": 153.0 },
+                { "value": 48.0, "target": 166.0 },
+                { "value": 49.0, "target": 179.0 },
+                { "value": 50.0, "target": 191.0 },
+                { "value": 51.0, "target": 204.0 },
+                { "value": 52.0, "target": 217.0 },
+                { "value": 53.0, "target": 230.0 },
+                { "value": 54.0, "target": 242.0 },
+                { "value": 55.0, "target": 255.0 }
+        ]
+      }
+    ]
+  },
+  {
+    "name": "Target mapping from Sys Inlet Temp",
+    "groups": [
+      {
+        "name": "Sys Inlet Temp",
+        "interface": "xyz.openbmc_project.Sensor.Value",
+        "property": { "name": "Value" }
+      }
+    ],
+    "triggers": [
+      {
+        "class": "poweron",
+        "method": "get_properties"
+      },
+      {
+        "class": "init",
+        "method": "get_properties"
+      },
+      {
+        "class": "signal",
+        "signal": "properties_changed"
+      },
+      {
+        "class": "timer",
+        "type": "repeating",
+        "interval": 5000000,
+        "preload_groups": true
+      }
+    ],
+    "actions": [
+      {
+        "name": "target_from_group_max",
+        "groups": [
+          {
+            "name": "Sys Inlet Temp",
+            "interface": "xyz.openbmc_project.Sensor.Value",
+            "property": { "name": "Value" }
+          }
+        ],
+        "neg_hysteresis": 2,
+        "pos_hysteresis": 0,
+        "map": [
+                { "value": 1.0, "target": 26.0 },
+                { "value": 10.0, "target": 51.0 },
+                { "value": 20.0, "target": 64.0 },
+                { "value": 25.0, "target": 77.0 },
+                { "value": 30.0, "target": 89.0 },
+                { "value": 35.0, "target": 102.0 },
+                { "value": 38.0, "target": 179.0 },
+                { "value": 40.0, "target": 255.0 }
+        ]
+      }
+    ]
+  }
+]
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/fans.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/fans.json
new file mode 100644
index 0000000..ad58857
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/fans.json
@@ -0,0 +1,44 @@
+[
+    {
+        "name": "FAN0",
+        "zone": "0",
+        "sensors": ["PWM7"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    },
+    {
+        "name": "FAN1",
+        "zone": "0",
+        "sensors": ["PWM5"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    },
+    {
+        "name": "FAN2",
+        "zone": "0",
+        "sensors": ["PWM4"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    },
+    {
+        "name": "FAN3",
+        "zone": "0",
+        "sensors": ["PWM3"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    },
+    {
+        "name": "FAN4",
+        "zone": "0",
+        "sensors": ["PWM1"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    },
+    {
+        "name": "FAN5",
+        "zone": "0",
+        "sensors": ["PWM0"],
+        "target_interface": "xyz.openbmc_project.Control.FanPwm",
+        "target_path": "/xyz/openbmc_project/control/fanpwm/"
+    }
+]
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/groups.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/groups.json
new file mode 100644
index 0000000..5baa063
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/groups.json
@@ -0,0 +1,134 @@
+[
+ {
+   "name": "fan inventory",
+   "members": [
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN0",
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN1",
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN2",
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN3",
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN4",
+     "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN5"
+   ]
+  },
+  {
+    "name": "fan0 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN0/FAN0_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN0/FAN0_R"
+    ]
+  },
+  {
+    "name": "fan1 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN1/FAN1_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN1/FAN1_R"
+    ]
+  },
+  {
+    "name": "fan2 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN2/FAN2_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN2/FAN2_R"
+    ]
+  },
+  {
+    "name": "fan3 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN3/FAN3_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN3/FAN3_R"
+    ]
+  },
+  {
+    "name": "fan4 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN4/FAN4_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN4/FAN4_R"
+    ]
+  },
+  {
+    "name": "fan5 rotor inventory",
+    "members": [
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN5/FAN5_F",
+      "/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard/FAN5/FAN5_R"
+    ]
+  },
+  {
+    "name": "CPU Temps",
+    "service": "xyz.openbmc_project.PLDM",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/S0_SOC_Pkg_Temp",
+      "/xyz/openbmc_project/sensors/temperature/S1_SOC_Pkg_Temp"
+    ]
+  },
+  {
+    "name": "PLDM Sensors",
+    "service": "xyz.openbmc_project.PLDM",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/S0_ThrotOff_Temp",
+      "/xyz/openbmc_project/sensors/temperature/S1_ThrotOff_Temp"
+    ]
+  },
+  {
+    "name": "CPU DIMM Temps",
+    "service": "xyz.openbmc_project.VirtualSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/S0_DIMMG0_Temp",
+      "/xyz/openbmc_project/sensors/temperature/S1_DIMMG0_Temp"
+    ]
+  },
+  {
+    "name": "NVMeM2 Max Temp",
+    "service": "xyz.openbmc_project.VirtualSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/NVMeM2_MaxTemp"
+    ]
+  },
+  {
+    "name": "NVMeFBP Max Temp",
+    "service": "xyz.openbmc_project.VirtualSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/NVMeFBP_MaxTemp"
+    ]
+  },
+  {
+    "name": "OCP Max Temp",
+    "service": "xyz.openbmc_project.VirtualSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/OCP_MaxTemp"
+    ]
+  },
+  {
+    "name": "PSU Max Temps",
+    "service": "xyz.openbmc_project.PSUSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/PSU0_TEMP",
+      "/xyz/openbmc_project/sensors/temperature/PSU1_TEMP"
+    ]
+  },
+  {
+    "name": "PCIE Zone Temps",
+    "service": "xyz.openbmc_project.HwmonTempSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/PcieZoneTemp1",
+      "/xyz/openbmc_project/sensors/temperature/PcieZoneTemp2"
+    ]
+  },
+  {
+    "name": "Sys Inlet Temp",
+    "service": "xyz.openbmc_project.VirtualSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/SysInletTemp"
+    ]
+  },
+  {
+    "name": "Sys Inlet Temp Components",
+    "service": "xyz.openbmc_project.HwmonTempSensor",
+    "members": [
+      "/xyz/openbmc_project/sensors/temperature/SysCabInletTemp",
+      "/xyz/openbmc_project/sensors/temperature/MBInletTemp1",
+      "/xyz/openbmc_project/sensors/temperature/MBInletTemp2",
+      "/xyz/openbmc_project/sensors/temperature/InletTemp"
+    ]
+  }
+
+]
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/monitor.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/monitor.json
new file mode 100644
index 0000000..9b2d592
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/monitor.json
@@ -0,0 +1,160 @@
+{
+    "fans": [
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN0",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN0_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM7",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN0_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM7",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       },
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN1",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN1_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM5",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN1_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM5",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       },
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN2",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN2_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM4",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN2_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM4",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       },
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN3",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN3_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM3",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN3_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM3",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       },
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN4",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN4_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM1",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN4_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM1",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       },
+       {
+          "inventory": "/system/board/Mt_Mitchell_Motherboard/FAN5",
+          "allowed_out_of_range_time": 12,
+          "deviation": 25,
+          "num_sensors_nonfunc_for_fan_nonfunc": 1,
+          "monitor_start_delay": 30,
+          "set_func_on_present": false,
+          "sensors": [
+             {
+                "name": "FAN5_F",
+                "has_target": true,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM0",
+                "factor": 90,
+                "offset": 0
+             },
+             {
+                "name": "FAN5_R",
+                "has_target": false,
+                "target_interface": "xyz.openbmc_project.Control.FanPwm",
+                "target_path": "/xyz/openbmc_project/control/fanpwm/PWM0",
+                "factor": 86,
+                "offset": 0
+             }
+          ]
+       }
+    ]
+ }
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-control@.service b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-control@.service
new file mode 100644
index 0000000..6ad9165
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-control@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Phosphor Fan Control Daemon
+Wants=xyz.openbmc_project.fansensor.service
+After=xyz.openbmc_project.fansensor.service
+StartLimitIntervalSec=30
+StartLimitBurst=3
+
+[Service]
+Restart=always
+ExecStart=-phosphor-fan-control
+RestartSec=20
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-monitor@.service b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-monitor@.service
new file mode 100644
index 0000000..83a2436
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-monitor@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Phosphor Fan Monitor Daemon
+Wants=xyz.openbmc_project.fansensor.service
+After=xyz.openbmc_project.fansensor.service
+StartLimitIntervalSec=30
+StartLimitBurst=3
+
+[Service]
+Restart=always
+ExecStart=-phosphor-fan-monitor
+RestartSec=20
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-presence-tach@.service b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-presence-tach@.service
new file mode 100644
index 0000000..64f6f8f
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/phosphor-fan-presence-tach@.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Phosphor Fan Presence Tach Daemon
+Wants=xyz.openbmc_project.fansensor.service
+After=xyz.openbmc_project.fansensor.service
+StartLimitIntervalSec=30
+StartLimitBurst=3
+
+[Service]
+Restart=on-failure
+ExecStart=phosphor-fan-presence-tach
+RestartSec=20
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/presence.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/presence.json
new file mode 100644
index 0000000..f0b5c46
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/presence.json
@@ -0,0 +1,98 @@
+[
+    {
+       "name": "FAN0",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN0",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN0_F",
+                "FAN0_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    },
+    {
+       "name": "FAN1",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN1",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN1_F",
+                "FAN1_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    },
+     {
+       "name": "FAN2",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN2",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN2_F",
+                "FAN2_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    },
+    {
+       "name": "FAN3",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN3",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN3_F",
+                "FAN3_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    },
+    {
+       "name": "FAN4",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN4",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN4_F",
+                "FAN4_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    },
+    {
+       "name": "FAN5",
+       "path": "/system/board/Mt_Mitchell_Motherboard/FAN5",
+       "methods": [
+          {
+             "type": "tach",
+             "sensors": [
+                "FAN5_F",
+                "FAN5_R"
+             ]
+          }
+       ],
+       "rpolicy": {
+          "type": "anyof"
+       }
+    }
+ ]
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/zones.json b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/zones.json
new file mode 100644
index 0000000..e87cdfa
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan/zones.json
@@ -0,0 +1,10 @@
+[
+    {
+        "name": "0",
+        "poweron_target": 153,
+        "default_ceiling": 255,
+        "default_floor": 64,
+        "increase_delay": 1,
+        "decrease_interval": 5
+    }
+]
diff --git a/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan_%.bbappend b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan_%.bbappend
new file mode 100644
index 0000000..3a4bbd0
--- /dev/null
+++ b/meta-ampere/meta-mitchell/recipes-phosphor/fans/phosphor-fan_%.bbappend
@@ -0,0 +1,42 @@
+FILESEXTRAPATHS:append := "${THISDIR}/${PN}:"
+
+PACKAGECONFIG:append = " json"
+
+SRC_URI:append = " \
+                  file://events.json \
+                  file://fans.json \
+                  file://groups.json \
+                  file://zones.json \
+                  file://monitor.json \
+                  file://presence.json \
+                  file://phosphor-fan-control@.service \
+                  file://phosphor-fan-monitor@.service \
+                  file://phosphor-fan-presence-tach@.service \
+                 "
+
+MITCHELL_COMPAT_NAME = "com.ampere.Hardware.Chassis.Model.MtMitchell"
+
+CONTROL_CONFIGS = "events.json fans.json zones.json groups.json"
+
+do_install:append () {
+        install -d ${D}${systemd_system_unitdir}
+        install -m 0644 ${WORKDIR}/phosphor-fan-monitor@.service ${D}${systemd_system_unitdir}
+        install -m 0644 ${WORKDIR}/phosphor-fan-control@.service ${D}${systemd_system_unitdir}
+        install -m 0644 ${WORKDIR}/phosphor-fan-presence-tach@.service ${D}${systemd_system_unitdir}
+
+        # datadir = /usr/share
+        install -d ${D}${datadir}/phosphor-fan-presence/control/${MITCHELL_COMPAT_NAME}
+        install -d ${D}${datadir}/phosphor-fan-presence/monitor/${MITCHELL_COMPAT_NAME}
+        install -d ${D}${datadir}/phosphor-fan-presence/presence/${MITCHELL_COMPAT_NAME}
+
+        for CONTROL_CONFIG in ${CONTROL_CONFIGS}
+        do
+                install -m 0644 ${WORKDIR}/${CONTROL_CONFIG} \
+                        ${D}${datadir}/phosphor-fan-presence/control/${MITCHELL_COMPAT_NAME}
+        done
+
+        install -m 0644 ${WORKDIR}/monitor.json \
+                ${D}${datadir}/phosphor-fan-presence/monitor/${MITCHELL_COMPAT_NAME}/config.json
+        install -m 0644 ${WORKDIR}/presence.json \
+                ${D}${datadir}/phosphor-fan-presence/presence/${MITCHELL_COMPAT_NAME}/config.json
+}